我有一个NSDocument
基于简单的 Mac OS X 应用程序,我正在尝试在其中实现 iCloud 文档存储。我正在使用 10.7 SDK 进行构建。
我已经为 iCloud 文档存储配置了我的应用程序,并包含了必要的权利 (AFAICT)。该应用程序正确构建、运行和创建本地通用容器 Documents 目录(这需要一段时间,但一切似乎都在工作)。我正在使用NSFileCoordinator
Apple 推荐的 API。我相当确定我使用的UbiquityIdentifier
是 Apple 推荐的正确方法(它在下面进行了编辑)。
我在这个 WWDC 2011 视频中密切关注 Apple 的 iCloud 文档存储演示说明:
会话 107 自动保存和 Lion 中的版本
我的代码看起来与该演示中的代码几乎相同。
但是,当我调用我的操作以将当前文档移动到云端时,我在调用该方法时遇到了活性问题。-[NSFileManager setUbiquitous:itemAtURL:destinationURL:error:]
它永远不会回来。
这是我的NSDocument
子类中的相关代码。它几乎与 Apple 的 WWDC 演示代码相同。由于这是一个动作,因此在主线程上调用它(如 Apple 的演示代码所示)。当调用该-setUbiquitous:itemAtURL:destinationURL:error:
方法时,死锁会在接近尾声时发生。我试过移动到后台线程,但它仍然永远不会返回。
似乎信号量在等待永远不会到达的信号时阻塞。
在调试器中运行此代码时,我的源 URL 和目标 URL 看起来是正确的,因此我相当确定它们计算正确,并且我已确认目录存在于磁盘上。
我是否在做任何明显错误的事情会导致-setUbiquitous
永远不会回来?
- (IBAction)moveToOrFromCloud:(id)sender {
NSURL *fileURL = [self fileURL];
if (!fileURL) return;
NSString *bundleID = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
NSString *appID = [NSString stringWithFormat:@"XXXXXXX.%@.macosx", bundleID];
BOOL makeUbiquitous = 1 == [sender tag];
NSURL *destURL = nil;
NSFileManager *mgr = [NSFileManager defaultManager];
if (makeUbiquitous) {
// get path to local ubiquity container Documents dir
NSURL *dirURL = [[mgr URLForUbiquityContainerIdentifier:appID] URLByAppendingPathComponent:@"Documents"];
if (!dirURL) {
NSLog(@"cannot find URLForUbiquityContainerIdentifier %@", appID);
return;
}
// create it if necessary
[mgr createDirectoryAtURL:dirURL withIntermediateDirectories:NO attributes:nil error:nil];
// ensure it exists
BOOL exists, isDir;
exists = [mgr fileExistsAtPath:[dirURL relativePath] isDirectory:&isDir];
if (!(exists && isDir)) {
NSLog(@"can't create local icloud dir");
return;
}
// append this doc's filename
destURL = [dirURL URLByAppendingPathComponent:[fileURL lastPathComponent]];
} else {
// get path to local Documents folder
NSArray *dirs = [mgr URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
if (![dirs count]) return;
// append this doc's filename
destURL = [[dirs objectAtIndex:0] URLByAppendingPathComponent:[fileURL lastPathComponent]];
}
NSFileCoordinator *fc = [[[NSFileCoordinator alloc] initWithFilePresenter:self] autorelease];
[fc coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForMoving writingItemAtURL:destURL options:NSFileCoordinatorWritingForReplacing error:nil byAccessor:^(NSURL *fileURL, NSURL *destURL) {
NSError *err = nil;
if ([mgr setUbiquitous:makeUbiquitous itemAtURL:fileURL destinationURL:destURL error:&err]) {
[self setFileURL:destURL];
[self setFileModificationDate:nil];
[fc itemAtURL:fileURL didMoveToURL:destURL];
} else {
NSWindow *win = ... // get my window
[self presentError:err modalForWindow:win delegate:nil didPresentSelector:nil contextInfo:NULL];
}
}];
}