如何防止与Realm和UICollectionView NSInternalInconsistencyException
我有一个从Realm填充的UICollectionView。有些用户,看似随意,得到NSInternalInconsistencyException说明像如何防止与Realm和UICollectionView NSInternalInconsistencyException
无效更新:在更新(73)之后的包含在现有的部分 项目的号段为0的项目无效的数量必须 等于到 更新(73)之前包含在该部分中的项目数,加上或减去从该部分插入或删除 的项目数(插入1个,删除0个),加上或减去移入或插入的项目数 在该部分(0移入,0移出)。
我的代码基于Realm的收集示例。它选择和过滤器的一些记录:
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无效更新: 无效第0项包含在 中的项目数的更新(78)之后的现有段的数目必须等于包含在该项目的数量 更新前的部分(78),加上或 减去从该部分插入或删除的项目数(插入了2个 ,删除了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
RealmGridController
是之前境界支持细粒度的通知,这是写了一个库,所以它实现了很多定制的逻辑来得到相同的结果。我强烈建议您恢复到原来的逻辑,因为它已经深深地融入了Realm本身。
要记住的一件重要事情是Realm查询结果是活动对象;它们会在每次运行循环迭代时自动更新,以包含自此发生的所有更改。因此,self.assets
的内容应始终与您的收藏视图显示的内容直接进行一对一关联。细粒度通知通知仅用作更新任何过时的UI元素的机制,并且在调用时,self.assets
将已处于最新状态。
您可能需要提供您的应用程序,因为它运行如何修改的self.assets
某些内容的更多信息。如何添加和删除元素?您的应用程序中是否存在并发性?
您需要非常小心,不要做任何手动UI更新,因为集合视图之前的状态和Realm假定需要更新的任何意外分歧都会产生这些不一致性异常。
对我来说,我有一个上拉,刷新了和无限加载下来。
当我想刷新,我删除我所有的对象只是Web服务调用之前得到新的新数据。
try! Realm().write {
let demands = Realm().objects(Demand.self)
for demand in demands {
Realm().delete(demand)
}
}
这是触发更改的通知,但有时间做了删除动画之前,我收到了一个新的项目Web服务的响应,创建NSInternalInconsistencyException
所以,我想:
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()
}
}
它的工作原理!这个想法是在通知被调用之前重载加载视图。 希望它可以帮助别人。
注:我没有任何问题的模拟器,只有真实iPhone 6的iOS设备10
如果只是调用reloadData,则不需要'insertItemsAtIndexPaths''reloadItems','deleteItems' – aelam
谢谢,这使得很多关于'RealmGridController'感。我会恢复。我的应用程序发生了相当数量的并发。由于它在此集合视图中显示图像,因此它会在后台拖动缩略图,并导致资产记录在领域中更新。我很小心将领域和对象保留在同一个线程中,并且我正在使用文档推荐的相同方式使用事务。我很高兴提供任何其他可能有用的细节。另外,在更新来自不同线程的记录时,有什么特别的地方需要注意? – SuitedSloth
不用担心!嗯,如果您在后台线程上对Realm进行了更改,则可能需要小心。在后台进行的更改将被合并,并且在运行循环的以下迭代中将在主线程中可见。如果你的UI在那之前做了不同的事情,那肯定会导致崩溃。或许值得回顾一下BG中Realm做了哪些变化,如果它们不太重,可以将它们提升到主线程。 – TiM