RealmSwift如何观察Category集合下关联TartuGecko的amount字段变更
Realm监听关联对象字段变更最优方案
核心思路
利用Realm官方提供的带键路径过滤的集合通知实现,既不需要单独给每个Category对象加观察者,也不需要全局监听所有TartuGecko实例,完全符合Realm数据处理规范,无内存泄漏风险,性能满足数千个实例的使用场景。
实现步骤
- 第一步:通过Realm查询拿到你需要监听的
CategoryTotal集合的Results实例,可通过filter方法限定你需要监听的分类范围,不要自行将Results转为数组持有,Realm原生Results是自动更新的轻量结构,无额外内存开销。 - 第二步:给上述Results添加监听时指定键路径为
total.amount,Realm底层会自动过滤,只有当前集合内CategoryTotal关联的TartuGecko的amount字段发生变更时才会触发通知,其他字段变更、其他无关TartuGecko实例的变更都不会触发回调。 - 第三步:强持有通知返回的
NotificationToken,在宿主对象销毁时主动调用invalidate释放监听,避免内存泄漏。
代码示例
监听注册逻辑
final class YourBusinessViewModel { // 强持有通知token private var categoryObserveToken: NotificationToken? func setupCategoryObserver() { do { let realm = try Realm() // 可根据业务需求加过滤条件,比如只监听指定id的分类 let observeCategories = realm.objects(CategoryTotal.self) // 指定监听键路径为total.amount,精准过滤变更事件 categoryObserveToken = observeCategories.observe(keyPaths: ["total.amount"], { [weak self] change in guard let self = self else { return } switch change { case .initial(let results): // 首次加载结果回调,可做初始数据渲染 self.handleInitialData(results: results) case .update(let results, _, _, let modifications): // modifications为发生变更的Category在集合中的下标 modifications.forEach { index in let category = results[index] let newTotal = category.total?.amount.doubleValue ?? 0 // 处理单个分类总额变更的业务逻辑 self.handleCategoryTotalUpdate(categoryId: category.categoryId, newTotal: newTotal) } case .error(let error): print("监听异常: \(error)") } }) } catch { print("Realm初始化失败: \(error)") } } // 业务逻辑方法,根据需要自行实现 private func handleInitialData(results: Results<CategoryTotal>) {} private func handleCategoryTotalUpdate(categoryId: String?, newTotal: Double) {} }
内存释放逻辑
extension YourBusinessViewModel { deinit { // 主动销毁监听,避免内存泄漏 categoryObserveToken?.invalidate() } }
方案优势
该方案是Realm官方推荐的关联对象字段变更监听方式,底层在数据库内核层完成变更过滤,不会做多余的遍历计算,性能远高于单个对象监听或全局监听的方案;仅通过1个token即可管理所有监听事件,没有冗余的对象持有,完全避免内存泄漏问题,完全适配数千个TartuGecko实例的使用场景。
内容的提问来源于stack exchange,提问作者Byron Coetsee
相关产品推荐
相关产品推荐

