我使用带有Realm结果的UITableView作为它的数据源。结果使用领域通知进行注册,并在发生更改时更新。但是,同一个表视图有一个搜索栏,可根据用户搜索查询过滤结果。这也可以正常工作,但如果通知侦听器识别出更新,则节和行计数不匹配。这样做的正确方法是什么?是否可以更新NotificationToken?
这是初始化通知令牌的代码:
let realm = try! Realm()
results = realm.objects(Person.self).filter("active = '1'").sorted(byProperty: "name", ascending: true)
// Observe Results Notifications
notificationToken = results?.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }
switch changes {
case .initial:
// Results are now populated and can be accessed without blocking the UI
tableView.reloadData()
break
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the UITableView
tableView.beginUpdates()
tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.endUpdates()
break
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
print("Error: \(error)")
break
}
}
此代码根据用户搜索输入更新结果:
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text!
if searchText.isEmpty == false {
results = results?.realm?.objects(Person.self).filter("active = '1'")
results = results?.filter("name BEGINSWITH[c] %@ OR lastName CONTAINS[c] %@", searchText, searchText)
results = results?.sorted(byProperty: "name", ascending: true)
self.tableView.reloadData()
}
else {
results = results?.realm?.objects(Person.self).filter("active = '1'").sorted(byProperty: "name", ascending: true)
self.tableView.reloadData()
}
}
如果搜索qwuery已经执行并且在更新领域数据库之前,则会发生NSRange异常。
答案 0 :(得分:6)
您在results
中覆盖updateSearchResults()
。通知和notificationToken
与特定的Results
对象和查询相关联。因此,如果您通过其他查询覆盖results
,则应停止先前的通知,然后向新的results
对象重新添加通知。
所以updateSearchResults()
方法应如下所示:
func updateSearchResults(for searchController: UISearchController) {
let searchText = searchController.searchBar.text!
if searchText.isEmpty == false {
results = results?.realm?.objects(Person.self).filter("active = '1'")
results = results?.filter("name BEGINSWITH[c] %@ OR lastName CONTAINS[c] %@", searchText, searchText)
results = results?.sorted(byProperty: "name", ascending: true)
}
else {
results = results?.realm?.objects(Person.self).filter("active = '1'").sorted(byProperty: "name", ascending: true)
}
notificationToken.stop()
notificationToken = results?.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
guard let tableView = self?.tableView else { return }
switch changes {
case .initial:
tableView.reloadData()
break
case .update(_, let deletions, let insertions, let modifications):
tableView.beginUpdates()
tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)
tableView.endUpdates()
break
case .error(let error):
print("Error: \(error)")
break
}
}
}