0

アプリでiCloudでコアデータを使用しています。私はiOS 6.1.3以下で正常に動作するいくつかのコードを使用していますが、iOS 6.1.3デバイスを使用している場合はドキュメントを作成して保存しません。

OSX 10.8.3 と xcode バージョン:4.6.2 を使用しています。

iOS 6.1.3 を使用している場合、以下のコードで実行が停止します。

[coordinator coordinateWritingItemAtURL:[managedDoc.persistentStoreOptions valueForKey:NSPersistentStoreUbiquitousContentURLKey] options:NSFileCoordinatorWritingForDeleting error:&logerror byAccessor:^(NSURL *newURL) {
    NSError * delError = nil;
    [[NSFileManager defaultManager] removeItemAtURL:newURL error:&delError];
    //if(delError)
        //NSLog(@"Error deleting transaction file .... , reason : %@",delError.localizedDescription); 
}];

コード全体を以下に示します。

-(void)saveManagegDocument{

if(iCloud){
NSError * error = nil;
[coordinator coordinateWritingItemAtURL:managedDoc.fileURL options:NSFileCoordinatorWritingForDeleting error:&error byAccessor:^(NSURL *newURL) {
    NSError * delError = nil;
    [[NSFileManager defaultManager] removeItemAtURL:newURL error:&delError];
    //if(delError)
        //NSLog(@"Error deleting data file .... , reason : %@",delError.localizedDescription); 
}];
NSError * logerror = nil;

[coordinator coordinateWritingItemAtURL:[managedDoc.persistentStoreOptions valueForKey:NSPersistentStoreUbiquitousContentURLKey] options:NSFileCoordinatorWritingForDeleting error:&logerror byAccessor:^(NSURL *newURL) {
    NSError * delError = nil;
    [[NSFileManager defaultManager] removeItemAtURL:newURL error:&delError];
    //if(delError)
        //NSLog(@"Error deleting transaction file .... , reason : %@",delError.localizedDescription); 
}];
}
[managedDoc saveToURL:managedDoc.fileURL 
     forSaveOperation:UIDocumentSaveForCreating 
    completionHandler:^(BOOL success) {
        if (success) {
            [managedDoc closeWithCompletionHandler:^(BOOL success) {
                [managedDoc openWithCompletionHandler:^(BOOL success) {
                    [self performSelectorOnMainThread:@selector(documentReady) withObject:nil waitUntilDone:NO];
                }];
            }];
        }
        else{
            [[[UIAlertView alloc] initWithTitle:@"Could not save or open core data database." message:nil delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil] show];
           // [self showMessage:@"Could not save or open core data database "];
            //NSLog(@"Could not save or open core data database ");
        }
    }];

}

誰でも私を助けてください。

事前に感謝します。

4

1 に答える 1

1

削除に関するドキュメントを参照すると、NSFileManager がスレッドセーフではないことがわかります。そのため、それを使用して removeItemAtURL を呼び出すときに、新しいインスタンスを割り当て/初期化する必要があります。これにより、実行が停止するデッドロックが発生している可能性があります。

また、このコードは必ずメイン スレッドから実行してください。私はそれを行うためにGCDを使用しています。ドキュメントを削除する私の方法は次のようになります...

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
   NSAssert(![NSThread isMainThread], @"Must be not be on main thread");
   // insert code here 
});

非同期ブロックを使用する場合は、非同期ブロックの作業が完了したら実行できる完了ブロックを提供して、次のアクションを安全に開始できるようにすることをお勧めします。非同期アクションですが、複数のアクションを順番に実行しているようです。これらを個別のメソッドに分割し、完了ブロックと調整するのが最善です。ドキュメントを削除するサンプル メソッドを次に示します。

- (void)deleteDocument:(UIDocument *)document withCompletionBlock:(void (^)())completionBlock {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{

        NSError *fileCoordinatorError = nil;

        [[[NSFileCoordinator alloc] initWithFilePresenter:nil] coordinateWritingItemAtURL:document.fileURL options:NSFileCoordinatorWritingForDeleting error:&fileCoordinatorError byAccessor:^(NSURL *newURL) {

            // extra check to ensure coordinator is not running on main thread
            NSAssert(![NSThread isMainThread], @"Must be not be on main thread");

            // create a fresh instance of NSFileManager since it is not thread-safe
            NSFileManager *fileManager = [[NSFileManager alloc] init];
            NSError *error = nil;
            if (![fileManager removeItemAtURL:newURL error:&error]) {
                NSLog(@"Error: %@", error);
                // TODO handle the error
            }

            if (completionBlock) {
                completionBlock();
            }
        }];
    });
}

次に、deleteDocument を指定して、ドキュメントが削除された後に実行される完了ブロックを指定できます。このすべての並行処理に注意する必要があります。

この非同期メソッドの作業が完了したら、ここから開始できます。

[self deleteDocument:document withCompletionBlock:^{
    // insert code for next action
}];

理論的には NSFileCoordinator がそれを処理しますが、コード内の [NSFileManager defaultManager] でデッドロックしている可能性があります。

これがどのように機能するか教えてください。私はドキュメントベースのアプリに取り組んできましたが、自動的に起こっていることがあり、まだすべてを理解することができないため、本当に大変でした。しかし、私はこのデッドロックの問題を理解したばかりなので、少なくともこのコードのスニペットをあなたと共有することができました.

于 2013-05-12T20:43:48.020 に答える