RxSwift+Realm绑定UITableView删除对象崩溃:RLMException求助
RLMException崩溃问题 我之前帮朋友排查过一模一样的问题,你遇到的'Object has been deleted or invalidated.'崩溃,核心原因是Realm对象被删除后,绑定到UITableView的Rx序列里还持有这个已失效的对象引用,当UITableView尝试访问这个无效对象的属性时,就触发了Realm的异常。
问题根源拆解
你用RxSwift把Realm的Results<T>查询结果直接绑定到UITableView,虽然Results是Realm的实时更新集合,但Rx默认的绑定逻辑不会自动过滤掉已经被删除/失效的对象。当你删除某个对象后,这个对象会变成isInvalidated == true的状态,但它还留在Rx的序列里,UITableView渲染时去读取它的属性,自然就会抛出异常。
分步骤解决方案
1. 手动过滤失效对象(不依赖第三方库)
在Rx绑定的序列里,添加一个过滤操作,只保留未失效的对象:
// 假设你的Realm模型是TodoItem realm.objects(TodoItem.self) .asObservable() // 过滤掉已失效的对象 .map { $0.filter { !$0.isInvalidated } } .bind(to: tableView.rx.items(cellIdentifier: "TodoCell")) { index, item, cell in cell.textLabel?.text = item.content } .disposed(by: disposeBag)
2. 确保删除操作在Realm写事务中执行
删除Realm对象必须在写事务里进行,这是Realm的强制要求,同时也能保证Results集合实时更新:
deleteFirstButton.rx.tap .subscribe(onNext: { [weak self] in guard let self = self else { return } let realm = try! Realm() if let firstItem = realm.objects(TodoItem.self).first { try! realm.write { realm.delete(firstItem) } } }) .disposed(by: disposeBag)
⚠️ 注意:不要在ViewModel或其他地方持有已删除对象的强引用,否则即使删除了,内存里的无效对象还是会被访问到。
3. 用RxRealm库简化绑定(推荐)
官方维护的RxRealm库已经帮我们处理了对象失效、集合更新的所有细节,用它来绑定Realm查询会更安全:
先在依赖管理工具中添加RxRealm,然后导入库使用:
import RxRealm // 用RxRealm的rx.observe()方法创建安全的Observable realm.objects(TodoItem.self) .rx.observe() .bind(to: tableView.rx.items(cellIdentifier: "TodoCell")) { index, item, cell in cell.textLabel?.text = item.content } .disposed(by: disposeBag)
rx.observe()会自动过滤无效对象,并且优化了Realm集合更新的通知逻辑,删除对象后UITableView会自动正确刷新,完全不会触发崩溃。
验证方法
按照上面的修改后,点击deleteFirst按钮,UITableView会自动移除被删除的行,同时不会再抛出RLMException异常。
内容的提问来源于stack exchange,提问作者Martyn

