ios - 使用 UICollectionView 观察领域 - 竞争条件
问题描述
我将Realm
其用作缓存层,这样每当数据呈现给用户时,它首先从数据库中获取并显示给用户。随后,发送服务器请求以获取最新版本的数据,将其与Realm
数据库同步并以UICollectionView
.
问题是,当从Realm
数据库中检索缓存数据并且UICollectionView
正在更新时,服务器更新请求有可能在UICollectionView
加载所有单元格之前完成,并且由于Results
列表是数据的实时集合,它可能有被修改。现在,例如,如果在服务器端删除了一个项目,则实时集合将少持有一个项目,因此会导致超出范围的异常。
话虽如此,考虑到在逐行询问每一行时可以更改Realm
这一事实,即使官方文档中提供的代码也不是线程安全的:results
UITableView
class ViewController: UITableViewController {
var notificationToken: NotificationToken? = nil
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
let results = realm.objects(Person.self).filter("age > 5")
// Observe Results Notifications
notificationToken = results.observe { [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()
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()
case .error(let error):
// An error occurred while opening the Realm file on the background worker thread
fatalError("\(error)")
}
}
}
deinit {
notificationToken?.invalidate()
}
}
我能想到解决这个问题的唯一方法是创建结果的深层副本,并使用 Semaphore 或类似方法同步观察函数的主体,以确保数据不会处于不一致状态,我认为这非常低效. (请注意,tableView.endUpdates()
这并不意味着UITableView
已经重新加载了所有数据,但它只是被分派到一个队列并准备好异步处理。)
我想听听任何建议如何以有效的方式实现这一点,从而消除上述竞争条件。
解决方案
您需要在主线程上完成所有 UI 更新。如果你这样做,第一组结果会更新主线程上的集合视图,当下一组结果也出现时,它将在主线程上排队,因此它会在第一组完成后更新。
推荐阅读
- android - 来自命令行的 avd 和来自 avd 管理器的 avd 有什么区别?
- vuejs2 - 尝试运行我的 vue js 应用程序时,我的 eslint 出错
- docusignapi - docusign 中的内容类型无效
- content-security-policy - 框架的内容安全策略。框架源与框架祖先
- python - 写入文件的 xml 字符串文字格式错误
- javascript - 交换对象属性 javascript
- java - 如何使用带有插入返回所需的 urlconnection 的 AsyncTask?
- javascript - 为什么 javascript 在浏览器控制台中显示 (66) [empty × 65, {...}]?
- javascript - 获取 Agora.io 语音讨论室中未发布流的用户列表
- swift - TokBox:使用修改后的像素缓冲区时“consumeFrame”崩溃