SwiftUI应用中Realm执行不通知观察者的写入事务崩溃如何解决
问题解决思路
错误根因
该错误明确说明传入commitWrite(withoutNotifying:)的NotificationToken,不属于当前执行写入操作的Realm实例。即使所有逻辑都运行在主线程,若创建令牌的Realm与写入用的Realm配置存在差异、或令牌关联了其他Realm实例的查询,就会触发该崩溃。
方案1:修复现有实现
核心逻辑是统一主线程使用的Realm实例,避免每次单独创建实例带来的不一致问题:
- 改造Realm单例,存储全局主线程Realm实例
class RealmSetup{ static let shared = RealmSetup() // 全局统一的主线程Realm实例,所有主线程Realm操作都使用该实例 let mainRealm: Realm! var tokenAlpha: NotificationToken? = nil var tokenBravo: NotificationToken? = nil private init() { // App启动时在主线程初始化,保证线程安全 mainRealm = try! Realm() } }
- 所有观察者创建逻辑统一使用该实例
class AlphaModel: ObservableObject{ static let shared = AlphaModel() init(){ RealmSetup.shared.mainRealm.objects(Alpha.self).observe { [weak self] _ in self?.objectWillChange.send() }.store(in: &RealmSetup.shared.tokenAlpha) } } class BravoModel: ObservableObject{ static let shared = BravoModel() init(){ RealmSetup.shared.mainRealm.objects(Bravo.self).observe { [weak self] _ in self?.objectWillChange.send() }.store(in: &RealmSetup.shared.tokenBravo) } }
- 写入操作统一使用该实例,且保证在主线程执行
// CloudKit回调后先切到主线程执行写入 DispatchQueue.main.async { let realm = RealmSetup.shared.mainRealm try! realm.write(withoutNotifying: [RealmSetup.shared.tokenAlpha, RealmSetup.shared.tokenBravo].compactMap{$0}) { // 执行modified属性更新等写入操作 } }
方案2:更简化的实现(推荐)
无需管理令牌列表,直接在观察者侧过滤同步相关的变更即可,后续新增观察者也不需要修改写入逻辑:
在观察回调中判断变更内容,如果仅修改了modified同步字段就不触发UI更新:
class AlphaModel: ObservableObject{ static let shared = AlphaModel() init(){ let realm = RealmSetup.shared.mainRealm RealmSetup.shared.tokenAlpha = realm.objects(Alpha.self).observe { [weak self] changes in switch changes { case .update(_, let deletions, let insertions, let modifications): // 过滤无实际业务变更、仅更新modified字段的情况 guard !deletions.isEmpty || !insertions.isEmpty || !modifications.isEmpty else { return } // 也可遍历变更对象的修改字段,仅当modified以外的字段变更时触发更新 self?.objectWillChange.send() default: self?.objectWillChange.send() } } } }
该方案彻底规避了令牌与Realm实例不匹配的问题,维护成本更低。
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

