Tod*_*orf 4 macos cocoa objective-c icloud icloud-api
我有一个NSDocument基于简单的Mac OS X应用程序,我正在尝试实现iCloud Document存储.我正在使用10.7 SDK构建.
我已经为iCloud文档存储配置了我的应用程序,并包含了必要的权利(AFAICT).该应用程序正确构建,运行和创建本地ubiquity容器文档目录(这需要一段时间,但这一切似乎都有效).我正在使用NSFileCoordinatorApple推荐的API.我很确定我使用的UbiquityIdentifier是苹果公司推荐的正确版本(它在下面进行了编辑).
我在此WWDC 2011视频中密切关注Apple的iCloud Document存储演示说明:
会话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];
}
}];
}
Run Code Online (Sandbox Code Playgroud)
我不知道这些是否是你问题的根源,但这里有一些我看到的东西:
-[NSFileManager URLForUbiquityContainerIdentifier:]可能需要一段时间,所以你不应该在主线程上调用它. 请参阅此博客文章的"查找Ubiquity容器"部分
在全局队列上执行此操作意味着您应该使用已分配NSFileManager而不是+defaultManager.
传递给byAccessor协调写入部分的块不保证在任何特定线程上被调用,因此您不应该NSWindows在该块内操作或呈现模态对话框或任何内容(除非您已将其调度回主队列) ).
我认为几乎所有的iCloud方法NSFileManager都会阻塞,直到完成.您所看到的可能是方法阻塞并且永远不会返回,因为事情配置不正确.我会对您的设置进行双重和三重检查,也许会尝试简化再现情况.如果仍然无法正常工作,请尝试提交错误或联系DTS.