2016-09-27 18 views
2

Realmから取り込まれたUICollectionViewがあります。更新後のセクション0内の項目の無効な数の既存のセクションに含まれる アイテムの数(73)は 等しくなければなりません:一見ランダムで一部のユーザーは、NSInternalInconsistencyExceptionはRealmとUICollectionViewでNSInternalInconsistencyExceptionを防ぐ方法

無効な更新のようなものを述べてもらいます 更新(73)の前にそのセクションに含まれるアイテムの数に、そのセクション(挿入された1個、削除された0)からの挿入または削除されたアイテムの数をプラスまたはマイナスし、プラスまたはマイナス(0は移動し、0は移動しました)。

マイコードはレルムのコレクション例に基づいています。これは、選択してフィルタレコードをいくつか:

self.assets = realm.objects(Asset.self).filter("is_deleted = false")

そしてそれはに加入しているとの通知を処理します。

self.assetsNotificationToken = self.assets!.addNotificationBlock(){ [weak self] (changes: RealmCollectionChange) in 

    guard let collectionView = self!.collectionView else { return } 

    guard let strongSelf = self else { return } 

    switch changes { 

     case .Initial: 

      collectionView.reloadData() 

     case .Update(let _, let deletions, let insertions, let modifications): 

      strongSelf.collectionView?.performBatchUpdates({ 

       collectionView.insertItemsAtIndexPaths(insertions.map { NSIndexPath(forRow: $0, inSection: 0) }) 

       collectionView.reloadItemsAtIndexPaths(modifications.map { NSIndexPath(forRow: $0, inSection: 0) }) 

       collectionView.deleteItemsAtIndexPaths(deletions.map { NSIndexPath(forRow: $0, inSection: 0) }) 

      }, completion: nil) 

     case .Error(let error): 

      log.error(error.localizedDescription) 
      break 

    } 

} 

カウントがから来ている:

override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 

    guard assets != nil else { 
     return 0; 
    } 

    return assets!.count 

} 

私は後でRealmGridControllerに切り替え

クラッシュの原因が見つからないため、RealmGridControllerに切り替えました。これは、Realmのコアコントリビュータが作成したパッケージであり、Realm + CollectionViewsで作業するために必要なすべての標準機能をカプセル化しています。

それはうまくいくように見え、まったく同じクラッシュを見始めました。

致命的な例外:NSInternalInconsistencyException無効更新: に含まれる項目の数既存のセクションの更新(78)の後セクション0の項目の 無効数は、その中に含まれるアイテムの数 に等しくなければなりません( が挿入され、0が削除された)項目の数を差し引いた数に移動した項目の数をプラスまたはマイナスした数(0が移動した、0は移動しました)。

Fatal Exception: NSInternalInconsistencyException 
0 CoreFoundation     0x1839dadb0 __exceptionPreprocess 
1 libobjc.A.dylib    0x18303ff80 objc_exception_throw 
2 CoreFoundation     0x1839dac80 +[NSException raise:format:] 
3 Foundation      0x184360154 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 
4 UIKit       0x18938b00c -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:] 
5 UIKit       0x18938e464 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] 
6 UIKit       0x18938e2e0 -[UICollectionView _performBatchUpdates:completion:invalidationContext:] 
7 UIKit       0x188d2c2a4 -[UICollectionView performBatchUpdates:completion:] 
8 RealmGridController   0x1014a8340 specialized RealmGridController.controllerDidChangeContent(RBQFetchedResultsController) ->() (RealmGridController.swift:316) 
9 RealmGridController   0x1014a687c @objc RealmGridController.controllerDidChangeContent(RBQFetchedResultsController) ->() (RealmGridController.swift) 
10 RBQFetchedResultsController 0x100ff8edc __112-[RBQFetchedResultsController calculateChangesWithAddedSafeObjects:deletedSafeObjects:changedSafeObjects:realm:]_block_invoke.433 (RBQFetchedResultsController.m:842) 
11 libdispatch.dylib    0x1834254bc _dispatch_call_block_and_release 

答えて

2

RealmGridControllerレルムは、きめの細かい通知をサポートしているので、同じ結果を得るために、カスタム・ロジックの多くを実装する前に書かれたライブラリです。私は強くレルム自体に深く組み込まれているので、元のロジックに戻すことを強くお勧めします。

覚えておくべき重要な点の1つは、レルムのクエリ結果がライブオブジェクトであることです。実行ループの各反復で自動的に更新され、その後に発生した変更が反映されます。その結果、self.assetsの内容は、コレクションビューで表示されているコンテンツの直接の1対1の相関でなければなりません。きめ細かい通知通知は、古いUI要素を更新するメカニズムとしてのみ機能し、呼び出されるまでにはself.assetsは既に最新の状態になります。

self.assetsの内容をアプリがどのように変更するかについて、さらに詳しい情報を提供する必要があります。要素はどのように追加され、削除されますか?ここにあなたのアプリで並行処理が起こっていますか?

コレクションビューの前の状態からの予期しない分岐や、Realmが更新する必要があると想定しているため、これらの矛盾の例外が発生するため、手動UIの更新を行わないように十分注意する必要があります。

+0

おかげで、上、シミュレータ上問題ありませんでした。私は元に戻す。私のアプリはかなりの並行処理を行っています。このコレクションビューでイメージを表示しているので、バックグラウンドでサムネイルが表示され、資産レコードが領域内で更新されます。私は、同じスレッド内で領域とオブジェクトを保持することに注意しています。私は、ドキュメントが推奨するのと同じ方法でトランザクションを使用しています。私は役に立つかもしれない他の詳細を提供してくれることを嬉しく思います。また、別のスレッドからレコードを更新する際に注意すべき点がありますか? – SuitedSloth

+0

心配はいりません!ええと、背景のスレッドでRealmに変更が加えられた場合は、注意が必要な場合があります。バックグラウンドで行われた変更は合体し、実行ループの次の反復でメインスレッドで表示されます。あなたのUIがそれまでに何か異なることをするなら、それは間違いなくクラッシュを引き起こす可能性があります。 BGでRealmに加えられた変更を見直すことは価値があるかもしれません。重すぎない場合は、主スレッドにそれらをプロモートすることもできます。 – TiM

1

私の場合、私はリフレッシュして、無限のロードをダウンさせました。

私がリフレッシュしたいとき、私はすべてのオブジェクトを削除して、Webサービスコールの直前に新しい新しいデータを取得していました。

try! Realm().write { 
    let demands = Realm().objects(Demand.self) 
    for demand in demands { 
     Realm().delete(demand) 
    } 
} 
変更通知をトリガーた

が、削除のためのアニメーションを実行する時間を持つ前に、私はNSInternalInconsistencyException

を作成し、1つの新しいアイテムを使用してWebサービスのレスポンスを受けていたので、私が試しました:

try! Realm().write { 
    let demands = Realm().objects(Demand.self) 
    for demand in demands { 
     Realm().delete(demand) 
    } 
} 
collectionView?.reloadData() 

これは機能しませんでした。その後、私はやってやった:

try! Realm().write { 
    let demands = Realm().objects(Demand.self) 
    for demand in demands { 
     Realm().delete(demand) 
     collectionView?.reloadData() 
    } 
} 

それは動作します!考えは、通知が呼び出される前にreloadCollectionViewを行うことです。 誰かを助けてくれることを願っています。

NB:私だけRealmGridController` `についての多くの意味を作る本物のiPhone 6デバイスのiOSの10

+0

reloadDataを単に呼び出すと、 'insertItemsAtIndexPaths'' reloadItems'、 'deleteItems'は不要ですが、 – aelam

関連する問題