使用RxSwift+RxRealm时,Realm更新对象属性出现删插而非更新问题
嘿,我来帮你分析下这个问题——你遇到的这种“更新变删插”的情况,在Realm+RxRealm的开发里其实挺常见的,大概率是几个细节没处理好,咱们一步步排查:
1. 先检查你的Item模型定义是否正确
首先要确保你的Item类完全符合Realm的模型要求,这是最容易踩坑的地方:
import RealmSwift class Item: Object { // 必须正确标记主键,Realm靠它识别唯一对象 @Persisted(primaryKey: true) var id: Int // 要修改的isNew属性必须用@Persisted标记,让Realm接管它的持久化 @Persisted var isNew: Bool // 其他属性... }
如果isNew是计算属性、没加@Persisted,或者主键设置错误,Realm就无法追踪这个属性的变更,甚至会把修改后的对象当成新实例重新插入,同时删除旧对象。
2. 确认Realm实例的线程安全性
Realm实例是线程绑定的——你在主线程创建的Realm实例,绝对不能拿到后台线程去操作,反之亦然。如果你的数据库单例是在主线程初始化的,但ViewModel的更新操作是在后台线程执行的,就会触发异常行为。
修改你的单例实现,确保每个线程都获取对应线程的Realm实例:
class RealmManager { static let shared = RealmManager() private init() {} // 每个线程调用这个方法获取当前线程的Realm实例 func getRealm() throws -> Realm { return try Realm() } func updateNew(for primaryKey: Int) throws { let realm = try getRealm() guard let itemToUpdate = realm.object(ofType: Item.self, forPrimaryKey: primaryKey) else { return } try realm.write { itemToUpdate.isNew = !itemToUpdate.isNew } } }
3. 排查RxRealm的订阅逻辑
你可以在订阅changeset时,打印更详细的变更信息,确认是不是真的执行了删插,而不是RxRealm的显示误解:
Observable.changeset(from: realm.objects(Item.self)) .subscribe(onNext: { (items, changes) in guard let changes = changes else { return } print("已删除索引:\(changes.deleted)") print("已插入索引:\(changes.inserted)") print("已更新索引:\(changes.updated)") }) .disposed(by: disposeBag)
如果changes.updated是空数组,而deleted和inserted有值,那说明Realm确实执行了删插操作,这时候回到前面的模型和线程问题继续排查。
4. 检查是否有其他代码干扰
有没有其他地方在处理Item对象时,不小心用了realm.add(item, update: .all)这类写法?比如如果重新创建了一个Item实例,再用add方法“更新”,Realm在某些情况下会先删除旧对象再插入新对象,而不是直接修改原有对象的属性。尽量避免这种写法,直接修改从Realm获取的对象才是正确的更新方式。
按照上面的步骤排查,大概率能解决你的问题——最常见的原因就是Realm实例跨线程使用,或者模型属性没被正确标记为Realm托管属性。
内容的提问来源于stack exchange,提问作者mikro098

