2016-04-19 13 views
0

「別名で保存」でコアデータドキュメントベースのアプリケーションがクラッシュする。保存」使用NSPersistentDocumentが「別名で保存」するとクラッシュする

  • 私がターゲット

    • とOS X 10.10ヨセミテ上で実行します。 問題は重要な違いは、そのこと「NSPersistentDocument objects "gutted" after Duplicate, Rename in 10.9

      というタイトルココア-devのスレッドで説明したものと同様のようです"重複ではなく"として "

    • クラッシュが先に発生します。 MOC保存中に

    この問題は、最も単純なNSPersistentDocumentでも影響します。それは少なくとも2014年以来のことです。したがって、私は他の人が同じ問題に遭遇したことを願っています。

    私のsample projectは、単一の属性を持つ単一のエンティティを使用します。エンティティのすべてのインスタンスを表示するためのテーブルビューと、新しいインスタンスを作成するためのボタンがあります。私はデフォルトテンプレートから、autosavesInPlaceを無効にするためだけに迷いました。

    クラッシュを再現する手順は次のとおりです。

    1. ビルドとヨセミテ上で実行します。バグは キャピタンにエルに固定されているよう
    2. 新しい文書
    3. を挿入し、新しいオブジェクト
    4. 保存文書
    5. 文書
    6. 再オープンに文書
    7. 変更を閉じますを作成します。テーブル内の属性の値
    8. 「名前を付けて保存」を使用して新しい名前で保存する
    OS Xヨセミテで210

    これは常に次のバックトレースでクラッシュ:

    _propertyAtIndexForEntityDescription() 
    snapshot_get_value_as_object() 
    -[NSManagedObject(_NSInternalMethods) _validatePropertiesWithError:]() 
    -[NSManagedObject(_NSInternalMethods) _validateForSave:]() 
    -[NSManagedObject validateForUpdate:]() 
    -[NSManagedObjectContext(_NSInternalAdditions) _validateObjects:forOperation:error:exhaustive:forSave:]() 
    -[NSManagedObjectContext(_NSInternalAdditions) _validateChangesForSave:]() 
    -[NSManagedObjectContext(_NSInternalChangeProcessing) _prepareForPushChanges:]() 
    -[NSManagedObjectContext save:]() 
    -[NSPersistentDocument writeToURL:ofType:forSaveOperation:originalContentsURL:error:]() 
    -[NSDocument _writeSafelyToURL:ofType:forSaveOperation:forceTemporaryDirectory:error:]() 
    -[NSDocument _writeSafelyToURL:ofType:forSaveOperation:error:]() 
    -[NSDocument writeSafelyToURL:ofType:forSaveOperation:error:]() 
    -[NSPersistentDocument writeSafelyToURL:ofType:forSaveOperation:error:]() 
    __66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_22353() 
    __66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke2350() 
    __66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_22222() 
    __110-[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:writingItemAtURL:options:error:byAccessor:]_block_invoke428() 
    -[NSFileCoordinator(NSPrivate) _invokeAccessor:orDont:andRelinquishAccessClaim:]() 
    -[NSFileCoordinator(NSPrivate) _coordinateReadingItemAtURL:options:writingItemAtURL:options:error:byAccessor:]() 
    -[NSDocument _fileCoordinator:coordinateReadingContentsAndWritingItemAtURL:byAccessor:]() 
    -[NSDocument _fileCoordinator:asynchronouslyCoordinateReadingContentsAndWritingItemAtURL:byAccessor:]() 
    __66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke2221() 
    -[NSDocument _prepareToSaveToURL:forSaveOperation:completionHandler:]() 
    __66-[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke() 
    -[NSDocument continueFileAccessUsingBlock:]() 
    -[NSDocument _performFileAccessOnMainThread:usingBlock:]() 
    -[NSDocument performAsynchronousFileAccessUsingBlock:]() 
    -[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]() 
    __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2() 
    -[NSDocument _commitEditingThenContinue:]() 
    __62-[NSPersistentDocument _documentEditor:didCommit:withContext:]_block_invoke() 
    

    編集1.可能な回避策:

    私が中に保存されてから、元の管理オブジェクトコンテキストを防止することにより、クラッシュの周りにパッチを適用することができます「別名で保存」操作"名前を付けて保存"した後、すぐに既存の文書を閉じて、新しい場所から文書を再度開きます。それはすべて非常に醜いので、他のNSPersistentDocumentの動作を破る可能性があります。この問題を回避する上

    編集2.クラッシュを回避しない省から元の管理対象オブジェクトコンテキストを防止保存されていない変更

    を失います。ただし、最終結果は、最後に保存された状態の文書のコピーです。未保存の変更は失われます。

    編集3.全焼のスナップショット

    時点で、古い管理対象オブジェクトコンテキストは新しいファイルに変更を保存しようとすると、オブジェクトのスナップショットは、もはやその実体<_CDSnapshot_Entity_: 0x600001f3cfd0> (entity: (null); id: 0x40000b <x-coredata://83B64FD3-B5B9-44CB-976D-54C0326FDFF5/Entity/p1> ; data: (null))を知りません。 -[_CDSnapshot entity]をサポートするインスタンス変数はありません。私はそれがオブジェクトIDからそれを見つけるべきであると仮定します。

    +0

    今、それは変わってきています。サンプルプロジェクトは、1台のEl Capitanマシンでクラッシュしますが、別のマシンではクラッシュしません。 サンプルアプリケーションがクラッシュしないマシンでは、「別名で保存」中にプロダクションが空のドキュメントを作成します。 –

    +0

    saveはパブリックメソッド 'validateForUpdate:'を呼び出しています。ドキュメントのオブジェクト上で直接呼び出すとどうなりますか? –

    +0

    '[super writeToURL:ofType:forSaveOperation:originalContentsURL:error:]'を呼び出す前に 'validateForUpdate:'を呼び出すとクラッシュすることはありません。私は問題は、既存の管理オブジェクトのコンテキストが新しい場所に書き込むときに呼び出されるときに発生すると思う。その時点で管理対象オブジェクトのプロパティが使用できなくなったようです。 –

    答えて

    0

    私の使用例ではうまくいくと思われる回避策が出てきました。

    - (BOOL)writeToURL:(NSURL *)absoluteURL 
          ofType:(NSString *)typeName 
        forSaveOperation:(NSSaveOperationType)saveOperation 
    originalContentsURL:(NSURL *)absoluteOriginalContentsURL 
          error:(NSError **)error 
    { 
        if ((saveOperation == NSSaveAsOperation) && (absoluteOriginalContentsURL != nil)) { 
         NSFileManager *fileManager = [NSFileManager defaultManager]; 
    
         if (![fileManager copyItemAtURL:absoluteOriginalContentsURL toURL:absoluteURL error:error]) { 
          return NO; 
         } 
    
         NSManagedObjectContext *managedObjectContext = self.managedObjectContext; 
         NSPersistentStoreCoordinator *persistentStoreCoordinator = managedObjectContext.persistentStoreCoordinator; 
         NSPersistentStore *store = [persistentStoreCoordinator persistentStoreForURL:absoluteOriginalContentsURL]; 
    
         [persistentStoreCoordinator setURL:absoluteURL forPersistentStore:store]; 
    
         if (![managedObjectContext save:error]) { 
          return NO; 
         } 
    
         return YES; 
        } 
    
        return [super writeToURL:absoluteURL 
              ofType:typeName 
            forSaveOperation:saveOperation 
           originalContentsURL:absoluteOriginalContentsURL 
               error:error]; 
    } 
    

    名前を付けて保存すると、古い文書が新しい(一時的な)場所にコピーされます。次に、永続ストアに新しいURLを設定し、管理対象オブジェクトのコンテキストに保留中の変更をその新しいドキュメントに保存させます。

    NSPersistentDocumentは、absoluteURLとして渡された一時URLの生成を処理し、保存されたファイルを新しい場所に移動し、保存が完了するとsetFileURL:を呼び出します。

    私は、ドキュメントをバックアップするSQLiteストアでジャーナリングを無効にしました。したがって、私はabsoluteOriginalContentsURLに1つのファイルだけをコピーする必要があります。

    関連する問題