我有一个名为 CardDetails 的模型
public class CardDetails: Object {
@objc public dynamic var id : Int = 0
@objc public dynamic var number : String?
@objc public dynamic var name : String?
@objc public dynamic var status : String?
override public static func primaryKey() -> String? {
return "id"
}
override public static func indexedProperties() -> [String] {
return ["status"]
}
}
当我们从 API 获取数据时,该对象被写入后台线程
let realm = try Realm()
try realm.write {
for card in cardsList {
realm.add(card,update: true)
}
}
我在 ViewController 中使用了如下的 NotificationToken
var cardResults: Results<CardDetails>!
override func viewDidLoad() {
super.viewDidLoad()
cardResults = realm.objects(CardDetails.self).filter("status = %@", "ACTIVE")
tokenCards = cardResults.observe { [weak self] (changes: RealmCollectionChange) in
switch(changes) {
case .initial, .update:
self?.setUpCardUI()
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
fatalError("\(error)")
}
}
}
问题是我在每次调用卡片获取端点时都会调用 setUpCardUI,尽管数据没有改变(只有一张事件卡片!)。这会导致意外的 UI 行为。
最佳答案
无论数据是否更改,Realm 都会在更新对象时始终发送修改更改,这很糟糕,但是,这并不意味着我们无法解决问题,甚至无法实现一些不错的改进。
我们不想在观察到更改时重新加载整个 TableView ,而是希望手动插入、删除或重新加载单元格。我写了一个扩展来在 tableview 上执行此操作。
import UIKit
// RealmDiff is just a lightweight struct to make passing the changes around cleaner
// public struct RealmDiff {
// let deletions: [Int]
// let insertions: [Int]
// let modifications: [Int]
//}
extension UITableView {
func reload(section: Int = 0, with diff: RealmDiff?, update: ((UITableViewCell, IndexPath) -> Void)? = nil) {
guard let diff = diff else {
reloadData()
return
}
beginUpdates()
insertRows(at: diff.insertions.map({ IndexPath(row: $0, section: section) }), with: .automatic)
deleteRows(at: diff.deletions.map({ IndexPath(row: $0, section: section) }), with: .automatic)
guard update != nil else {
reloadRows(at: diff.modifications.map({ IndexPath(row: $0, section: section) }), with: .fade)
endUpdates()
return
}
endUpdates()
let indexPaths = diff.modifications
.map ({ IndexPath(row: $0, section: 0) })
.filter { indexPathsForVisibleRows?.contains($0) ?? false }
indexPaths.forEach {
if let cell = cellForRow(at: $0) {
update?(cell, $0)
}
}
}
}
默认情况下,这仍会交换所有单元格,这可能仍会导致表格 View 跳转,具体取决于您的布局实现。但是我们也可以传递一个闭包来手动更改单元格上的数据。以下是正在使用的扩展的示例:
tableView.reload(with: diff) { [weak self] cell, indexPath in
if let cell = cell as? MyCellClass {
MyCellClass.configure(cell: cell, with: myDataSourceDataArray[indexPath.row], delegate: self)
}
}
这样您就可以使用同一个单元格,无需重新加载。我发现这种方法非常有效并且可重复使用。
关于ios - Realm swift : Results getting notifications even though there is no data change (Swift),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50673131/