无法创建 UIManagedDocument
Posted
技术标签:
【中文标题】无法创建 UIManagedDocument【英文标题】:Could not create UIManagedDocument 【发布时间】:2013-12-01 14:43:20 【问题描述】:我正在尝试使用 Core Data 制作 iPhone 应用程序。我必须使用NSManagedObjectContext
来访问数据,为此我使用UIManagedDocument
。但是如果我尝试使用UIManagedDocument
创建一个文档,则文档的openWithCompletionHandler
不会成功。这就是为什么我的NSManagedObjectContext
总是nil
而Xcode 说无法在等处创建文档。这里是类:
AddUserViewController.h
#import <UIKit/UIKit.h>
@interface AddUserViewController : UIViewController
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic,strong) UIManagedDocument *document;
@end
AddUserViewController.m
#import "AddUserViewController.h"
#import "User.h"
#import "User+Create.h"
@interface AddUserViewController ()
@property (weak, nonatomic) IBOutlet UITextField *nameField;
@property (weak, nonatomic) IBOutlet UITextField *ageField;
@property (weak, nonatomic) IBOutlet UITextField *sexField;
@property (weak, nonatomic) IBOutlet UITextField *weightField;
@property (weak, nonatomic) IBOutlet UITextField *activityField;
@end
@implementation AddUserViewController
-(void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
_managedObjectContext = managedObjectContext;
-(void)createOrWriteDocument
NSURL *url = [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentationDirectory inDomains:NSUserDomainMask]firstObject];
url = [url URLByAppendingPathComponent:@"Activities"]; // edited mistakenly deleted
self.document = [[UIManagedDocument alloc] initWithFileURL:url];
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]])
[self.document openWithCompletionHandler:^(BOOL success)
if (success) [self documentIsReady];
if (!success)
NSLog(@"could not open document at %@",url);
];
else
[self.document saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success)
if (success)
[self documentIsReady];
if (!success)
NSLog(@"could not create document at %@",url);
];
- (void)documentIsReady
if (self.document.documentState == UIDocumentStateNormal)
self.managedObjectContext = self.document.managedObjectContext;
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view.
if (!self.managedObjectContext)
[self createOrWriteDocument];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:@selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
-(void)dismissKeyboard
[self.nameField resignFirstResponder];
[self.ageField resignFirstResponder];
[self.sexField resignFirstResponder];
[self.weightField resignFirstResponder];
[self.activityField resignFirstResponder];
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
if ([segue.identifier isEqualToString:@"setUser:"])
//User *user = [[User alloc]init];
User *user = [User createUserWithname:self.nameField.text
withAge:[NSNumber numberWithDouble:[self.ageField.text doubleValue]]
withSex:self.sexField.text
withWeight:[NSNumber numberWithDouble:[self.weightField.text doubleValue]]
withActivity:self.activityField.text
inManagedObjectContext:self.managedObjectContext];
if ([segue.destinationViewController respondsToSelector:@selector(setUser:)])
[segue.destinationViewController performSelector:@selector(setUser:) withObject:user];
@end
编辑
我解决了问题。问题在NSURL *url = [[[NSFileManager defaultManager]URLsForDirectory:NSDocumentationDirectory inDomains:NSUserDomainMask]firstObject];
线。我使用 NSDocumentDirectory 而不是 NSDocumentationDirectory,它解决了问题。
【问题讨论】:
我将 UIManagedDocument 用于我正在开发的应用程序,我看到的唯一主要区别是我将文档名称附加到 url 路径的末尾。我还从 fileManager 中获取了 lastObject。 Ex.NSURL * managedDocumentURLPath = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; managedDocumentURLPath = [managedDocumentURLPath URLByAppendingPathComponent:@"AppNameDocument"]; 当我删除了注释行-在这里写代码-时,我删除了这一行。相同的代码,但我失败了。 【参考方案1】:你可以试试这段代码来创建你的 managedobjectcontext。
- (NSManagedObjectContext *) managedObjectContext
if (_managedObjectContext != nil)
return _managedObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
return _managedObjectContext;
【讨论】:
【参考方案2】:看看下面的例子。这对我有用,抱歉没有时间仔细查看差异,我正在使用 iCloud 选项,因此请删除它们,但尝试设置其他 persistentStoreOptions。并发布错误的详细信息?
// This gets called when the user has done one of the following:
// 1. Created a new file and entered a new file name. We have then created the fileURL
// using the /Documents directory, the filename and appending '_UUID_'+uuid to ensure that
// avoid duplicate file names in case the user used the same file name on another device.
// 2. Selected an existing file from the file browser
//
- (void)createNewFile:(NSURL*)fileURL
//FLOG(@"createNewFile called with url %@", fileURL);
_creatingNewFile = YES; // Ignore any file metadata scan events coming in while we do this because some iCloud
// files get created by Core Data before the local files are created and our scanning
// picks up new iCloud files and attempts to create local copies and we don't want this
// if this devices is busy creating the new iCloud file
_document = [[OSManagedDocument alloc] initWithFileURL:fileURL];
// Set oberving on this file to monitor the state (we don't use it for anything other than debugging)
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(documentStateChanged:)
name:UIDocumentStateChangedNotification
object:_document];
_openedVersion = [NSFileVersion currentVersionOfItemAtURL:fileURL];
_openedVersionDate = _openedVersion.modificationDate;
_openedVersionDevice = _openedVersion.localizedNameOfSavingComputer;
//FLOG(@" file version date: %@", _openedVersionDate);
//FLOG(@" file version device: %@", _openedVersionDevice);
NSString *fileName = [[fileURL URLByDeletingPathExtension] lastPathComponent];
[_document setPersistentStoreOptions:@NSPersistentStoreUbiquitousContentNameKey:fileName,
NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES,
NSSQLitePragmasOption:@ @"journal_mode" : @"DELETE" ];
_managedObjectContext = _document.managedObjectContext;
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
//FLOG(@" file exists so open it: %@",fileURL);
[_document openWithCompletionHandler:^(BOOL success)
if (!success)
// Handle the error.
LOG(@" error creating file");
else
//LOG(@" file opened");
[self fileOpened]; // Now initialise the UI and let the user continue...
];
else
// File does not exist so that means the user has created a new one and we need to
// load some initialisation data into the Core Data store (codes tables, etc.)
//
// At this stage we have a database in memory so we can just use the _document.managedObjectContext
// to add objects prior to attempting to write to disk.
//LOG(@" file DOES NOT exist so add initial data");
[self addInitialData];
// Just checking if anything has been written to disk, nothing should not exist on disk yet.
// Debugging use only
if ([[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]])
LOG(@" file exists but keep going anyway :-(");
else
LOG(@" file still does not exist :-)");
// OK now save a copy to disk using UIManagedDocument
// NOTE: the iCloud files are written before the UIManagedDocument.fileURL, presumably because Core Data does this setup
// in response to the [moc save:]. Make sure we don't pick this up in our iCloud metaData scan and attempt to create
// it as if it were a new iCloud file created by some other device.
//
[_document saveToURL:_document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
if (!success)
// Handle the error.
LOG(@" error saving file :-(");
// We close the file and wait for it to appear in the file browser and then
// let the user select it from the browser to open it and start using it.
// Skip this if you want to open it directly and [self fileopened] but
// bear in mind the fileListController will not be correctly set up when we return to it.
[_document closeWithCompletionHandler:^(BOOL success)
if (!success)
// Handle the error.
LOG(@" error closing file after creation :-(");
FLOG(@" file URL is %@", [fileURL path]);
else
FLOG(@" file closed %@", fileName);
_creatingNewFile = NO; // OK we are done, so let metaData scanning go ahead as normal
// Tell our UITableView file list that we are done and trigger scanning of local and iCloud files
// The fileListController will the add the new file itself and the user will then pick the
// file from this list in order to open it.
// To open the file automatically use the callback in the fileListController
// to select and then open the file so it looks seamless to the user.
[self.fileListController fileHasBeenCreated:fileURL];
// Stop observing now
[center removeObserver:self
name:UIDocumentStateChangedNotification
object:_document];
];
];
哦,还要创建一个 UIManagedDocument 的子类,这样你就可以得到错误,如果你还没有错误的话。您只需要子类中的以下内容。
@implementation OSManagedDocument
- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
LOG(@"Auto-Saving Document");
return [super contentsForType:typeName error:outError];
- (void)handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted
FLOG(@" error: %@", error.localizedDescription);
NSArray* errors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(errors != nil && errors.count > 0)
for (NSError *error in errors)
FLOG(@" Error: %@", error.userInfo);
else
FLOG(@" error.userInfo = %@", error.userInfo);
@end
这是获取设备上 /Documents 目录的方法。文件名附加到此路径。
- (NSURL*)documentsDirectoryURL
_dataDirectoryURL = [NSURL fileURLWithPath:NSHomeDirectory() isDirectory:YES];
return [_dataDirectoryURL URLByAppendingPathComponent:@"Documents"];
这里是更多信息的链接http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/
【讨论】:
以上是关于无法创建 UIManagedDocument的主要内容,如果未能解决你的问题,请参考以下文章