NSDocument
iCloudドキュメントストレージを実装しようとしている単純なベースのMac OS Xアプリがあります。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 デモ コードとほぼ同じです。これは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];
}
}];
}