NSBatchDeletereQueStereQuestマージの競合を引き起こします -- ios フィールド と swift フィールド と core-data フィールド と swift4 フィールド と xcode9 フィールド 関連 問題

NSBatchDeleteRequest causes Merge Conflict












5
vote

問題

日本語

私は毎日変わることができるデータを含むサーバと同期するアプリケーションを持っています。同期中に、いくつかのエンティティのすべてのデータを削除し、新しいデータでリロードします。私は次のコードを使っています:

<事前> <コード> func SyncronizeUserComments(theData : [[AnyHashable : Any]]) { // Delete User Comments for this User and Connection let commentRequest : NSFetchRequest<NSFetchRequestResult> = PT_UserComments.fetchRequest() commentRequest.predicate = NSPredicate(format: "connection = %@ AND user == %@", Global_CurrentConnection!, Global_CurrentUser!) coreData.processDeleteRequest(request: commentRequest) // ADD the Comments to CoreData for index in 0..<theData.count { let result : [AnyHashable : Any] = theData[index] if let commentID = result["Comment_ID"] as? String, let commentText = result["Comment_Text"] as? String, let commentTitle = result["Comment_Title"] as? String { let newUserComment = PT_UserComments(context: coreData.persistentContainer.viewContext) newUserComment.connection = Global_CurrentConnection newUserComment.user = Global_CurrentUser newUserComment.comment_ID = commentID newUserComment.comment_Text = commentText newUserComment.comment_Title = commentTitle } } // Add the User Comments print("Added New User Comments: (theData.count)") coreData.saveContext() } func processDeleteRequest(request : NSFetchRequest<NSFetchRequestResult>) { let deleteRequest = NSBatchDeleteRequest(fetchRequest: request) deleteRequest.resultType = .resultTypeObjectIDs do { let result = try coreData.persistentContainer.viewContext.execute(deleteRequest) as? NSBatchDeleteResult let objectIDArray = result?.result as? [NSManagedObjectID] let changes = [NSDeletedObjectsKey : objectIDArray] NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes as Any as! [AnyHashable : Any], into: [coreData.persistentContainer.viewContext]) } catch { fatalError("Fatal Error Deleting Data: (error)") } coreData.saveContext() }

CoreData.SaveContext()を呼び出すと、削除されたデータに対してマージの競合が発生します。

CoreDataとNSBatchDeletereQueStereQueStについて読み込む際には、これはSQL Liteレベルで削除され、INメモリキャッシュをバイパスします。

これを機能させることができた唯一の方法は、設定によるものです。

<事前> <コード> context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy

これは正しいですか、それとも間違ったことをしていますか?コアデータスタックのMy SaveContext()でこのマージポリシーも設定しています。

英語

I have an application that will sync with a server with data that can change daily. During the sync, I remove all the data for some entities and reload it with new data. I am using the following code:

    func SyncronizeUserComments(theData : [[AnyHashable : Any]]) {     // Delete User Comments for this User and Connection     let commentRequest : NSFetchRequest<NSFetchRequestResult> = PT_UserComments.fetchRequest()     commentRequest.predicate = NSPredicate(format: "connection = %@ AND user == %@", Global_CurrentConnection!, Global_CurrentUser!)     coreData.processDeleteRequest(request: commentRequest)      // ADD the Comments to CoreData     for index in 0..<theData.count {         let result : [AnyHashable : Any] = theData[index]         if let commentID = result["Comment_ID"] as? String, let commentText = result["Comment_Text"] as? String, let commentTitle = result["Comment_Title"] as? String         {             let newUserComment = PT_UserComments(context: coreData.persistentContainer.viewContext)             newUserComment.connection = Global_CurrentConnection             newUserComment.user = Global_CurrentUser             newUserComment.comment_ID = commentID             newUserComment.comment_Text = commentText             newUserComment.comment_Title = commentTitle         }     }      // Add the User Comments     print("Added New User Comments: (theData.count)")     coreData.saveContext() }      func processDeleteRequest(request : NSFetchRequest<NSFetchRequestResult>) {     let deleteRequest = NSBatchDeleteRequest(fetchRequest: request)     deleteRequest.resultType = .resultTypeObjectIDs      do {         let result = try coreData.persistentContainer.viewContext.execute(deleteRequest) as? NSBatchDeleteResult         let objectIDArray = result?.result as? [NSManagedObjectID]         let changes = [NSDeletedObjectsKey : objectIDArray]         NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes as Any as! [AnyHashable : Any], into: [coreData.persistentContainer.viewContext])     } catch  {         fatalError("Fatal Error Deleting Data: (error)")     }      coreData.saveContext() } 

When I call coreData.saveContext() I will get a Merge Conflict against the deleted data.

In reading about CoreData and the NSBatchDeleteRequest, this deletes at the SQL LITE level and bypasses the in memory cache.

The only way I have been able to get this to work is by setting:

context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy 

Is this correct, or am I doing something wrong? I am also setting this merge policy in my saveContext() in the Core Data Stack.

</div
              

回答リスト

2
 
vote
vote
ベストアンサー
 

私はちょうど同じ問題をデバッグする時間を費やしました、うまくいけばこれは誰かを助けることができます。

問題は、 NSManagedObjectContext.mergeChanges(fromRemoteContextSave:, into:) が管理対象オブジェクトのコンテキストを更新するが、更新されたバージョン番号に一致する削除されたオブジェクト関係の行キャッシュのバージョン番号を更新しない(<コード> Z_OPT )。データベースファイルで、保存時に不一致を引き起こします。

NSErrorMergePolicyType を使用している場合、バージョン番号が一致していても、次の保存は失敗した(または、関係が保存のためにフラグが立てられたときに後の後で)失敗することがあります。私はこれを関連するドキュメントまたはWWDCのビデオで言及されているのを見ませんでしたが、私は人々が常にデフォルト以外のマージポリシーを選ぶだろうと仮定していると思います。

SO NSMergeByPropertyStoreTrumpMergePolicy を選択すると、それを解決しますが、質問で述べたように解決しますが、すべての保存操作に対してこのポリシーが必要ない場合があります。バージョンの不一致のみを解決するカスタムマージポリシーを作成したことを避けるために。コードは以下の通りです(これはもともとOBJ-Cで書いたときは未テストの迅速ですが、同等であるべきです):

<事前> <コード> //Configure the merge as below before saving context.mergePolicy = AllowVersionMismatchMergePolicy(merge: .errorMergePolicyType) //... //The custom merge policy class AllowVersionMismatchMergePolicy: NSMergePolicy { override func resolve(optimisticLockingConflicts list: [NSMergeConflict]) throws { do { //if the default resolve worked leave it alone return try super.resolve(optimisticLockingConflicts: list) } catch { //if any of the conflict is not a simple version mismatch (all other keys being equal), fail let hasValueConflict = list.contains { conflict -> Bool in //compare object and row cache if let objectSnapshot = conflict.objectSnapshot as NSObject?, let cachedSnapshot = conflict.cachedSnapshot as NSObject? { return !objectSnapshot.isEqual(cachedSnapshot) } //compare row cache and database if let cachedSnapshot = conflict.cachedSnapshot as NSObject?, let persistedSnapshot = conflict.persistedSnapshot as NSObject? { return !cachedSnapshot.isEqual(persistedSnapshot) } //never happens, see NSMergePolicy.h return true } if hasValueConflict { throw error } //Use store rollback merge policy to resolve all the version mismatches return try NSMergePolicy.rollback.resolve(optimisticLockingConflicts: list) } } }
 

I just spent hours debugging the same issue, hopefully this can help someone.

The problem is that NSManagedObjectContext.mergeChanges(fromRemoteContextSave:, into:) updates the managed object context but does not update the row cache version number of the deleted objects relationships to match the updated version number (Z_OPT) in the database file, causing a mismatch at time of the save.

If you're using NSErrorMergePolicyType this will cause the next save to fail, (or even a later one when the relationships become flagged for save), even though everything but the version numbers match. I've not seen this mentioned in the related docs or WWDC video, but I guess Apple assumed people would always pick a non-default merge policy.

So picking NSMergeByPropertyStoreTrumpMergePolicy solves it, as mentioned in the question, but you might not want this policy for all your save operations. To avoid that I ended up writing a custom merge policy that only resolves version mismatches. The code is below (this is untested Swift as I originally wrote in Obj-C, but should be equivalent):

 //Configure the merge as below before saving context.mergePolicy = AllowVersionMismatchMergePolicy(merge: .errorMergePolicyType)  //...  //The custom merge policy class AllowVersionMismatchMergePolicy: NSMergePolicy {     override func resolve(optimisticLockingConflicts list: [NSMergeConflict]) throws {         do {             //if the default resolve worked leave it alone             return try super.resolve(optimisticLockingConflicts: list)         } catch {             //if any of the conflict is not a simple version mismatch (all other keys being equal), fail             let hasValueConflict = list.contains { conflict -> Bool in                 //compare object and row cache                 if let objectSnapshot = conflict.objectSnapshot as NSObject?,                     let cachedSnapshot = conflict.cachedSnapshot as NSObject? {                     return !objectSnapshot.isEqual(cachedSnapshot)                 }                 //compare row cache and database                 if let cachedSnapshot = conflict.cachedSnapshot as NSObject?,                     let persistedSnapshot = conflict.persistedSnapshot as NSObject? {                     return !cachedSnapshot.isEqual(persistedSnapshot)                 }                 //never happens, see NSMergePolicy.h                 return true             }             if hasValueConflict {                 throw error             }              //Use store rollback merge policy to resolve all the version mismatches             return try NSMergePolicy.rollback.resolve(optimisticLockingConflicts: list)         }     } }   
</div
 
 

関連する質問

6  Xcode 9スペルチェックグレーアウト  ( Xcode 9 spell check greyed out ) 
私はXcode9に更新されていたので、スペルチェッカー機能を使用できません。例えば。編集する&gtに進みます。フォーマット&gt;スペル&アンプ文法は、すべてのスペルチェッカーのオプションを「スペルと文法」とは別に採点しています。 ショースペルと文法をクリッ...

10  iOS 11ナビゲーションバーオーバーラップステータスバー  ( Ios 11 navigation bar overlap status bar ) 
IOS 11のナビゲーションバーはオーバーラップステータスバーです。いずれかの体が同じ問題に直面した場合は親切に助けてください。 ...

360  iOS 11、Apple TV 4KなどでXcode 9でワイヤレスデバッグを実行するにはどうすればよいですか。  ( How do you perform wireless debugging in xcode 9 with ios 11 apple tv 4k etc ) 
ワイヤレスデバッグは最近Xcode 9、iOS 11、およびTVOS 11の機能として追加されました.Apple TV 4KにはUSBポートがありませんので、ワイヤレスデバッグが必要です。このワイヤレスデバッグをどのようにXcodeに実行しますか? ...

1  [UICTFONT ISEQUALTOSTRING:]:認識されていないセレクターが送信されました  ( Uictfont isequaltostring unrecognized selector sent ) 
私はこの問題に直面しています。Xcode 9とiOS 11のみです。それが発生している場所の背中の痕跡さえ得られない。アプリは私にこのエラーを与えることによってクラッシュするだけです。 ...

1  COREML(.mlModelファイル)でエラーを取得しますか?  ( Getting errors in coreml mlmodel file ) 
Xcode 9 BetaでSWIFT 4.0でCOREMLを使用しています。 WWDCからInception v3.mlModelファイルをダウンロードしました 未解決の識別子 'inceptionv3'のエラーを使用すると、宣言型 'inceptionv...

4  NSXPCConnectionデバッグ割り込み/無効化  ( Nsxpcconnection debugging interruption invalidation ) 
Xcode 9、OSXはIOS、Objective-C。 他のアプリケーションと通信するためのXPCサービスを持っています。 XPCサービスは私にとって全く新しいです。私が見つけたドキュメントや記事を読んでください - それでも私はいくつかの助けが必要です。...

41  Xcode 9で失敗しました  ( Rename failed in xcode 9 ) 
「名前の変更」機能を使用して、Xcode 9で "DefaultRequestURL"という名前の変数の名前を変更し、それを警告します。 アラートイメージ ファイル "composecontroller.swift"をチェックしました、 "DefaultReq...

3  Xcode 9シミュレータが遅くなります  ( Xcode 9 simulator slow ) 
Xcode 9 iOS 11 Simulatorが初めてアプリを実行すると非常に遅くなります。誰かが同じ経験を経験しましたか? スローアニメーションシミュレータの特徴はすでにチェックされています。 ...

1  PODにAlamoFireが追加されたAlamofireが追加されたビルドタイムエラースウィフト4 Xcode 9  ( Build time error swift 4 xcode 9 with alamofire added in pod ) 
私は私がSWIFT 4をサポートするために更新されたプロジェクトに取り組んでいました4.関連する変更を行った後、私がアプリケーションを実行した後、私は以下のように似たようなエラーが発生しました。その後、私は同じエラーも発生したものをチェックするための新しく空の...

7  iOSアプリのエラー:コマンド/ usr / bin / codesignが終了コード1で失敗しました1  ( Error for ios app command usr bin codesign failed with exit code 1 ) 
iOS用のIONIC3アプリを持っています。昨日まで私はXcode9の.xcodeProjを開き、私のiPhoneにアプリをアップロードすることができました。私は何が悪かったのかわかりませんでしたが、このエラーは「コード1を終了して失敗しました」というエラー...




© 2022 cndgn.com All Rights Reserved. Q&Aハウス 全著作権所有