NSPredicate 更改时不会触发领域通知
Posted
技术标签:
【中文标题】NSPredicate 更改时不会触发领域通知【英文标题】:Realm Notification is not triggered when NSPredicate changes 【发布时间】:2016-11-22 21:48:49 【问题描述】:我在 Realm 中有一个简单的勾选列表,我使用 NotificationToken
检查数据源中的更新,然后使用以下项目更新 tableView:
class Item : Object
dynamic var name = ""
dynamic var isTickedOff = false
dynamic var timeStamp : Date?
型号:
var items: Results<Item>
get
let results = self.realm.objects(Item.self)
let alphabetic = SortDescriptor(property: "name", ascending: true)
let tickedOff = SortDescriptor(property: "isTickedOff", ascending: true)
let timestamp = SortDescriptor(property: "timeStamp", ascending: false)
return results.sorted(by: [tickedOff, timestamp, alphabetic]).filter("isTickedOff = %@ || isTickedOff = %@", false, self.includeAll)
我的表格视图中有一个开关,用户可以在其中更改self.includeAll
属性。
在插入、删除或选择项目时(导致将它们设置为isTickedOff
或!isTickedOff
)会触发通知并更新tableView。但是,即使修改了items
属性,更改self.includeAll
属性也不会触发通知。我可以在用户触发开关时包含self.tableView.reloadData()
,但我希望通过通知获得更流畅的动画。
是我,谁把通知理解错了还是bug?
提前致谢!
【问题讨论】:
【参考方案1】:Realm 不观察外部属性,因此它无法知道在谓词查询中使用的属性何时发生更改,并随后生成更改通知。
当您下次访问items
时,这将为其提供足够的事件来重新计算内容,但到那时,它不会触发通知。
显然,正如您所说,最简单的解决方案是简单地调用tableView.reloadData()
,因为这将强制重新获取items
,但不会有动画。或者相反,like this SO question says,您可以调用 tableView.reloadSections
来实际启用“重新洗牌”动画。
最后,这可能是一个相当肮脏的 hack,但如果您仍然希望它触发基于 Realm 的更改通知,您可能只打开一个 Realm 写入通知,更改 includeAll
属性,然后关闭写入尝试“欺骗”Realm 执行更新的事务。
最后一点。我可能没有足够的信息,所以这可能是不正确的,但是如果您在 items
属性上注册一个领域通知块,请注意您实现该 getter 的方式意味着生成了一个新对象每次调用它。将该属性标记为lazy
可能更合适,以便在第一次调用后保存。
【讨论】:
感谢您的回答,@TiM。 'tableView.reloadSections' 可以解决问题并且看起来比'tableView.reloadData' 更平滑。更改写入事务中的“includeAll”属性似乎并不能解决问题。我实际上希望“items.addNotificationBlock”能够监听“items”属性的变化,即使底层领域没有任何变化。 不用担心@Krabbas!很高兴我能帮上忙!啊,好吧。至少知道这一点很好。更改通知块会在底层 Realm 数据发生更改时做出响应,从而更改Results
对象的内容。当与依赖外部属性的NSPredicate
复合时,它会变得更加复杂。以上是关于NSPredicate 更改时不会触发领域通知的主要内容,如果未能解决你的问题,请参考以下文章
更改 NSFetchedResultsController 的 fetchRequest.predicate 不会触发委托