5

iCloudの競合を解決するために、調整された書き込みブロック内でクラスメソッドを単純に呼び出すように見えるものを使用しています。NSFileVersionremoveOtherVersionsOfItemAtURL:

デバイスが「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 がスローされるのは奇妙だと思います。

4

1 に答える 1

2

呼び出し時に次のことに気付きました。

[NSFileVersion otherVersionsOfItemAtURL:theURL]

への呼び出しの直前にremoveOtherVersionsOfItemAtURL:、戻り値は nil であり、(ドキュメントを介して) 次のことを示します。

戻り値: ファイル バージョン オブジェクトの配列、またはそのようなファイルがない場合は nil。配列には、currentVersionOfItemAtURL: メソッドによって返されたバージョン オブジェクトが含まれていません。

そのため、 を呼び出す前にこのメソッドの戻り値を確認することでremoveOtherVersionsOfItemAtURL:、問題が軽減されました。しかし、そのメソッドが単純に を返したり、単に提供されたオブジェクトを設定したりするのではなく、EXC_BAD_ACCESSによって がスローされるのは奇妙だと思います。removeOtherVersionsOfItemAtURL:NONSError

レーダーを提出し、返信があり次第ここで更新します。

于 2012-09-05T11:57:53.473 に答える