9

s を使用してデータを保存するUIDocumentベースのアプリがあります。NSFileWrapper「マスター」ファイル ラッパーには、多くの追加のディレクトリ ファイル ラッパーが含まれており、それぞれがドキュメントの異なるページを表します。

UIDocumentの保存中に ( で) ドキュメントに変更を加えるたびにwriteContents:andAttributes:safelyToURL:forSaveOperation:error:、アプリがクラッシュします。スタック トレースは次のとおりです。

UIDocument クラッシュ スタック トレース

UIDocumentバックグラウンドで列挙しているファイルラッパーの同じインスタンスを変更していることは明らかです。実際、私は、データ モデルのスナップショットを返すときにcontentsForType:error:、返されたサブ ファイル ラッパーが、コピーではなく、データ モデルに現在存在する (および編集されている) オブジェクトと同じオブジェクトを指していることを確認しました。

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
    if (!_fileWrapper) {
        [self setupEmptyDocument];
    }
    return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]];
}

これは、このメソッドを実装するための認可されたアプローチです ( WWDC 2012 Session 218 - Using iCloud with UIDocument によると)。

だから私は質問だと思います:このアプローチはどのようにしてスレッドセーフになることができますか?

マスター ファイル ラッパーfileWrappers自体がディレクトリ ファイル ラッパーである場合、状況は多少異なりますか? 認可されたアプローチが間違っている場合、それはどのように行われるべきですか?

4

2 に答える 2

8

いずれかのwriteContents:...メソッドを呼び出している場合は、そうすべきではありません。saveToURL:forSaveOperation:completionHandler:代わりに電話する必要があります。これらのwriteContents:...メソッドは、高度なサブクラス化を目的としています。

UIDocumentメインスレッドと「UIDocumentFileAccess」スレッドの2つのスレッドを使用します(これをさらにサブクラス化するとUIDocument、を介して処理を実行できますperformAsynchronousFileAccessUsingBlock:)。

スレッドセーフUIDocumentは、Objective Cの場合と同様です。オブジェクトを所有するスレッドにのみ、オブジェクトを変更させます。変更するオブジェクトが読み取られている場合は、書き込みの完了後に変更されるようにキューに入れます。UIDocumentおそらく、サブクラスが所有する別のオブジェクトを変更し、それらをの新しいオブジェクトにプルNSFileWrapperしますcontentsForType:error:。fileWrappersのコピーを渡しNSDictionaryます。

NSFileWrapper実際にドキュメント全体をメモリにロードします。はNSFileWrapper実際にはメソッドの「UIDocumentFileAccess」スレッドで作成され、readFromURL:error:メソッドに渡されloadFromContents:ofType:error:ます。大きなドキュメントがある場合、これにはしばらく時間がかかることがあります。

保存するときは、通常、UIDocumentこれをいつ実行するかを決定し、メソッドを介して何かが変更されたことを通知しupdateChangeCount:ます(paramはUIDocumentChangeDone)。今すぐ何かを保存したいときは、saveToURL:forSaveOperation:completionHandler:メソッドを使用したいと思います。

注意すべきもう1つのことは、使用するメソッドを定義するプロトコルをUIDocument実装することです。サブファイルではなく、ルートドキュメントへの書き込みを調整するだけです。ドキュメント内のサブファイルを調整することは役立つと思うかもしれませんが、発生するクラッシュは、辞書が繰り返されている間に辞書を変更することに関連しているため、役に立ちません。(1)ファイルの変更の通知を受け取りたい場合、または(2)別のオブジェクトまたはアプリが同じファイルに対して読み取り/書き込みを行っていた場合にのみ、自分で書き込むことを心配する必要があります。すでに行っていることはうまくいきます。ただし、ドキュメント全体を移動/削除するときに使用する必要があります。NSFilePresenterNSFileCoordinatorUIDocumentNSFilePresenterUIDocumentNSFileCoordinator

于 2013-03-12T03:24:06.117 に答える