我正在创建一个具有 iCloud 支持的新 UIManagedDocument,如下所示:
- 使用本地沙盒 URL 分配和初始化
- 设置持久存储选项以支持 iCloud:ubiquitousContentNameKey 和 ubiquitousContentURL。我唯一生成的名称和 URL 指向我的 ubiquityContainer / CoreData。
- 使用 UIManagedDocument 的 saveToURL 方法在本地保存到沙箱。
- 在完成处理程序中,使用 FileManager 的 setUbiquitous 方法移动到 iCloud。
到目前为止,这种舞蹈有效。(嗯,有点)。在我调用 setUbiquitous 后,我收到一个错误,说它不成功,但是文档移动到了云端。完成后,我在云中有一个新文档。这似乎是一个错误,因为我已经能够用其他人的代码复制它。
我实际上是在“文档视图控制器”中生成此文档,其中列出了云中的所有文档。因此,当这个新文档的最终完成处理程序完成时,由于 NSMetadataQuery,它会显示在表格视图中。到目前为止,我认为非常标准的用法。
要编辑文档,用户点击并转到“单视图文档视图控制器”。
在这个视图控制器中,我需要“重新打开”选定的文档,以便用户可以编辑它。
所以我再次经历了一系列步骤:
- 使用 fileURL 分配 / 初始化 UIManagedDocument —— 这次,URL 来自云端。
- 使用相同的设置设置我的持久存储选项,与上面的步骤 2 相同。
现在,我尝试了第 3 步,即从磁盘打开文档,但它失败了。文档处于“Closed | SavingError”状态并且尝试打开失败。
有谁知道为什么我的文档会创建 OK,移动到云 OK,但是在随后的立即尝试中无法打开?(实际上,在该应用程序的启动中进行了一次尝试 - 见下文)。具体来说,什么会使 UIManagedDocument 实例被创建但处于关闭、不可打开的状态?
有趣的是,如果我退出应用程序并再次启动,我可以点击并重新加载文档并进行编辑。
偶尔我可以很简单地创建、打开和编辑,比如插入一个托管对象,然后它进入关闭状态 | 保存错误状态。
错误信息:
我将 UIManagedDocument 子类化并覆盖了 -handleError: 方法以尝试获取更多信息,这就是我得到的(以及我放入的其他一些调试日志):
2012-10-05 14:57:06.000 基础 [23687:907] 单个文档视图控制器视图已加载。文档:fileURL:file://localhost/private/var/mobile/Library/Mobile%20Documents/7PB5426XF4~com~howlin~MyApp/Documents/New%20Document%2034/documentState:[关闭]
2012-10-05 14:57:06.052 MyApp[23687:907] 文档状态已更改。当前状态:5 文件URL:file://localhost/private/var/mobile/Library/Mobile%20Documents/7PB5426XF4~com~howlin~MyApp/Documents/New%20Document%2034/ documentState:[关闭 | 保存错误]
2012-10-05 14:57:06.057 Foundations [23687:5303] UIManagedDocument 错误:商店名称:新文档 34 已在使用中。存储 URL:file://localhost/private/var/mobile/Library/Mobile%20Documents/7PB5426XF4~com~howlin~MyApp/Documents/New%20Document%2034/StoreContent.nosync/persistentStore 正在使用存储 URL:file:/ /localhost/var/mobile/Applications/D423F5FF-4B8E-4C3E-B908-11824D70FD34/Documents/New%20Document%2034/StoreContent.nosync/persistentStore
2012-10-05 14:57:06.059 MyApp[23687:5303] { NSLocalizedDescription = "商店名称:新文档 34 已在使用中。\n\t商店 URL:file://localhost/private/var/mobile/ Library/Mobile%20Documents/7PB5426XF4~com~howlin~MyApp/Documents/New%20Document%2034/StoreContent.nosync/persistentStore\n\t 使用商店 URL:file://localhost/var/mobile/Applications/D423F5FF-4B8E -4C3E-B908-11824D70FD34/Documents/New%20Document%2034/StoreContent.nosync/persistentStore\n"; NSPersistentStoreUbiquitousContentNameKey = "新文档 34"; }
该错误似乎认为我正在创建一个在随后打开时已经存在的商店。我现在应该在第二次打开时在持久存储上设置这些 iCloud 选项吗?我已经尝试过这种方法,但它也没有奏效。
我研究了关于 UIManagedDocument 的斯坦福讲座,但看不出我做错了什么。
这是我创建文档并迁移到云的方法:
- (void) testCreatingICloudDocWithName:(NSString*)name
{
NSURL* cloudURL = [self.docManager.iCloudURL URLByAppendingPathComponent:name isDirectory:YES];
NSURL* fileURL = [self.docManager.localURL URLByAppendingPathComponent:name];
self.aWriting = [[FNFoundationDocument alloc] initWithFileURL:fileURL];
[self setPersistentStoreOptionsInDocument:self.aWriting];
[self.aWriting saveToURL:fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (success == YES) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//create file coordinator
//move document to icloud
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
NSError* coorError = nil;
[fileCoordinator coordinateWritingItemAtURL:cloudURL options:NSFileCoordinatorWritingForReplacing error:&coorError byAccessor:^(NSURL *newURL) {
if (coorError) {
NSLog(@"Coordinating writer error: %@", coorError);
}
NSFileManager* fm = [NSFileManager defaultManager];
NSError* error = nil;
NSLog(@"Before set ubiq");
[fm setUbiquitous:YES itemAtURL:fileURL destinationURL:newURL error:&error];
if (!error) {
NSLog(@"Set ubiquitous successfully.");
}
else NSLog(@"Error saving to cloud. Error: %@", error);
NSLog(@"State of Doc after error saving to cloud: %@", self.aWriting);
}];
});
}
}];
}
这是我在persistentStore上为iCloud设置选项的地方:
- (void)setPersistentStoreOptionsInDocument:(FNDocument *)theDocument
{
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[options setObject:[theDocument.fileURL lastPathComponent] forKey:NSPersistentStoreUbiquitousContentNameKey];
NSURL* coreDataLogDirectory = [self.docManager.coreDataLogsURL URLByAppendingPathComponent:[theDocument.fileURL lastPathComponent]];
NSLog(@"Core data log dir: %@", coreDataLogDirectory);
[options setObject:coreDataLogDirectory forKey:NSPersistentStoreUbiquitousContentURLKey];
theDocument.persistentStoreOptions = options;
}
这是我尝试重新打开它的地方:
- (void) prepareDocForUse
{
NSURL* fileURL = self.singleDocument.fileURL;
if (![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
NSLog(@"File doesn't exist");
}
else if (self.singleDocument.documentState == UIDocumentStateClosed) {
// exists on disk, but we need to open it
[self.singleDocument openWithCompletionHandler:^(BOOL success) {
if (!success) {
NSError* error;
[self.singleDocument handleError:error userInteractionPermitted:NO];
}
[self setupFetchedResultsController];
}];
} else if (self.singleDocument.documentState == UIDocumentStateNormal) {
// already open and ready to use
[self setupFetchedResultsController];
}
}