使用RealmSwift与SwiftUI在当前视图修改记录且不返回上级导航
问题解决:Realm视图修改数据不返回上级且实时刷新
核心问题
通过@ObservedResults从Realm获取订单对象后,在详情页(OrderView)执行删除订单项操作时,会自动返回上级导航视图,同时需要实现数据修改后视图实时同步刷新。想知道如何将已存储的Realm对象转为@StateRealmObject,以及更优的实现方案。
最优实现方案
核心思路是用@StateRealmObject直接持有当前订单对象,替代通过@ObservedResults二次查询的方式,同时修正Realm写入逻辑,避免父视图因集合更新导致的重绘跳转。
步骤1:修改OrderView,使用@StateRealmObject
直接在详情页持有订单对象,无需通过ID再次查询,同时利用@StateRealmObject的自动监听特性实现视图实时刷新:
struct OrderView: View { // 用@StateRealmObject持有当前订单,自动监听对象变化 @StateRealmObject var currentOrder: Order // 初始化直接传入解冻后的订单对象 init(currentOrder: Order) { self._currentOrder = StateRealmObject(wrappedValue: currentOrder) } func deleteOrderLine(id: String, sku: String) { guard let realm = currentOrder.realm else { return } do { try realm.write { // 直接从当前订单的订单项列表中查找并删除 let lineToDelete = currentOrder.orderLineId.first { $0.id == id && $0.productSku == sku } if let line = lineToDelete { realm.delete(line) } } } catch { print("删除订单项失败:\(error)") } } var body: some View { // 展示订单数据,遍历currentOrder.orderLineId List(currentOrder.orderLineId) { line in HStack { Text(line.productSku) Spacer() Button("删除") { deleteOrderLine(id: line.id, sku: line.productSku) } .foregroundColor(.red) } } .navigationTitle(currentOrder.name) } }
步骤2:修改父视图OrderListView2,直接传递解冻后的对象
避免传递ID再查询,直接将解冻后的订单对象传给详情页,减少不必要的Realm查询,同时避免父视图集合更新导致的跳转:
struct OrderListView2: View { @ObservedResults(Order.self) var allOrders var body: some View { NavigationStack { // iOS 16+用NavigationStack,旧版本用NavigationView List(allOrders.sorted(byKeyPath: "dateCreated", ascending: false)) { order in // 传递解冻后的订单对象给详情页 NavigationLink(destination: OrderView(currentOrder: order.thaw()!)) { Text(order.name) } } .navigationTitle("订单列表") } } }
关键说明
- 为什么之前会返回上级?
父视图的allOrders是@ObservedResults,当子视图删除订单项后,订单对象的orderLineId列表发生变化,触发allOrders更新,父视图的List会重新渲染,导致NavigationLink被重建,从而回到上级页面。用@StateRealmObject持有单个对象后,子视图的依赖是单个对象,父视图的集合更新不会影响子视图的导航状态。 @StateRealmObject的作用
自动监听Realm对象的变化,当对象的属性或关联列表修改时,会自动触发视图刷新;同时持有对象的强引用,保证对象在视图生命周期内有效。- 解冻对象的必要性
@ObservedResults返回的是冻结对象(Frozen Objects),无法直接修改,所以需要调用thaw()获取可写入的对象实例。
内容的提问来源于stack exchange,提问作者MoLoW
相关产品推荐
相关产品推荐

