【发布时间】:2026-01-22 00:55:01
【问题描述】:
我有一个简单的基于NSDocument 的 Mac OS X 应用程序,我正在尝试在其中实现 iCloud 文档存储。我正在使用 10.7 SDK 进行构建。
我已为 iCloud 文档存储配置了我的应用程序,并包含了必要的权利 (AFAICT)。该应用程序正确构建、运行和创建本地通用容器 Documents 目录(这需要一段时间,但一切似乎都在工作)。我正在使用 Apple 推荐的 NSFileCoordinator API。我很确定我使用的是 Apple 推荐的正确的 UbiquityIdentifier(它在下面被删节了)。
我在这个 WWDC 2011 视频中密切关注 Apple 的 iCloud 文档存储演示说明:
第 107 节自动保存和 Lion 中的版本
我的代码看起来与该演示中的代码几乎相同。
但是,当我调用我的 action 以将当前文档移动到云端时,我在调用 -[NSFileManager setUbiquitous:itemAtURL:destinationURL:error:] 方法时遇到了liveness 问题。它永远不会回来。
这是来自我的NSDocument 子类的相关代码。它几乎与 Apple 的 WWDC 演示代码相同。由于这是一个 action,因此在主线程上调用它(如 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];
}
}];
}
【问题讨论】:
标签: objective-c macos cocoa icloud icloud-api