iCloudの競合を解決するために、調整された書き込みブロック内でクラスメソッドを単純に呼び出すように見えるものを使用しています。NSFileVersion
removeOtherVersionsOfItemAtURL:
デバイスが「spaz モード」 (少数のデバイスでアプリケーションを繰り返し開いたり閉じたりすることを指す技術用語) になると、EXC_BAD_ACCESS
例外が内部的にスローされます。コードスニペット:
- (void)compareVersionChanges:(NSFileVersion *)version {
if (![DataLoader iCloudPreferenceEnabled]) {
NSLog(@"Ignoring iCloud changes (version comparison) based on user preference");
return;
}
NSLog(@"compareVersionChanges");
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue, ^(void) {
NSError *readError = nil;
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:(id)self];
[coordinator coordinateReadingItemAtURL:[version URL] options:0 error:&readError byAccessor:^(NSURL *newURL) {
DataContext *loadedContext = nil;
NSData *data = [NSData dataWithContentsOfURL:newURL];
NSError *e = nil;
loadedContext = [self convertXmlDataToContext:data error:&e];
if (e) {
NSLog(@"Done loading, error: %@", e);
[[DataLoader applicationDelegate] displayError:e];
loadedContext = nil;
}
if (!loadedContext) {
return;
}
id appDelegate = [DataLoader applicationDelegate];
DataContext *inMemoryContext = nil;
if (appDelegate != nil && [appDelegate respondsToSelector:@selector(context)]) {
inMemoryContext = [appDelegate performSelector:@selector(context)];
}
if (inMemoryContext) {
NSLog(@"Performing iCloud context synchronizating...");
DataContextSynchronizer *synchronizer = [[DataContextSynchronizer alloc] init];
ChangeSet *changes = [synchronizer compareLocalContext:inMemoryContext andRemoteContext:loadedContext];
if ([[changes changes] count] > 0) {
[SelectionManager disable];
@synchronized(appDelegate) {
NSLog(@"Applying synchronization changes...");
[synchronizer applyChangeSet:changes toDataContext:inMemoryContext];
NSLog(@"Synchronization changes applied");
}
[SelectionManager enable];
if ([appDelegate respondsToSelector:@selector(setSkipRefreshSave:)]) {
[appDelegate performSelector:@selector(setSkipRefreshSave:) withObject:[NSNumber numberWithBool:YES]];
}
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^(void) {
[SelectionManager notifyListeners];
});
if ([appDelegate respondsToSelector:@selector(setSkipRefreshSave:)]) {
[appDelegate performSelector:@selector(setSkipRefreshSave:) withObject:[NSNumber numberWithBool:NO]];
}
[self save:[[DataLoader applicationDelegate] context]];
} else {
NSLog(@"No sync changes applicable.");
}
NSError *coordinateWriteRemoveError = nil;
[coordinator coordinateWritingItemAtURL:newURL options:NSFileCoordinatorWritingForDeleting error:&coordinateWriteRemoveError byAccessor:^(NSURL *theURL) {
theURL = [theURL copy];
NSError *removeOtherVersionsError = nil;
[NSFileVersion removeOtherVersionsOfItemAtURL:theURL error:&removeOtherVersionsError];
if (removeOtherVersionsError) {
NSLog(@"Error removing other versions: %@", removeOtherVersionsError);
}
}];
if (coordinateWriteRemoveError) {
NSLog(@"Error occurred coordinating write for deletion of other file versions: %@", coordinateWriteRemoveError);
}
}
}];
if (readError) {
NSLog(@"Done loading (outside block) error: %@", readError);
}
});
}
少し構文を強調表示すると、これを調べやすくなると思いました。
Xcode のコード スニペットと失敗スタックの画像へのリンク
エラーは実際には1404 行で発生し、下のスクリーンショットからわかるように、Apple コードの領域に深く関わっています。
レーダーを提出する前に、ここで何か間違ったことをしていないか確認しようと思いましたか? 1402 行目の余分な[... copy]
部分は、ブロックが提供する引数への参照が失われていないことを確認するための簡単なチェックであり、削除されます。
編集:重要な注意!ARCを使用しています。
編集2:私は呼び出し時に気づいた:
[NSFileVersion otherVersionsOfItemAtURL:theURL]
戻り値はnil
であり、これは (ドキュメントを介して) 以下を示します。
...またはそのようなファイルがない場合は nil。配列には、currentVersionOfItemAtURL: メソッドによって返されたバージョン オブジェクトが含まれていません。
そのため、 を呼び出す前にこのメソッドの戻り値を確認することでremoveOtherVersionsOfItemAtURL:
、問題が軽減されました。しかし、そのメソッドが適切に処理するのではなく、EXC_BAD_ACCESS がスローされるのは奇妙だと思います。