You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中CoreData保存后ListView不刷新问题求助

SwiftUI+CoreData+MVVM列表不自动刷新问题解决

问题根源

核心问题是ContentView和FlightsListView各自创建了独立的FlightListViewModel实例:

  • ContentView内的flightListVM与FlightsListView内的flightListVM是两个完全独立的对象
  • 关闭弹窗时ContentView的onDismiss调用的是自身VM的getAllFlights(),不会同步到FlightsListView的VM数据,因此列表无法自动更新

解决方案

1. 共享ViewModel实例

在父层级(如ContentView或App)创建唯一的FlightListViewModel,再传递给FlightsListView,确保两个视图共用同一个VM:

修改ContentView代码

struct ContentView: View {
    @StateObject private var flightListVM = FlightListViewModel() // 全局唯一实例
    @State private var isPresented = false

    var body: some View {
        TabView {
            // 将共享VM传递给FlightsListView
            FlightsListView(flightListVM: flightListVM)
                .tabItem {
                    Image(systemName: "airplane")
                    Text("Flights")
                }
            // 其他标签页代码...
        }
        .sheet(isPresented: $isPresented, onDismiss: {
            // 调用共享VM的刷新方法
            flightListVM.getAllFlights()
        }) {
            NewFlightView()
        }
    }
}

修改FlightsListView代码

struct FlightsListView: View {
    // 改为@ObservedObject,接收外部传递的VM实例
    @ObservedObject var flightListVM: FlightListViewModel
    @State private var isPresented: Bool = false

    private func deleteFlight(at indexSet: IndexSet) {
        indexSet.forEach { index in
            let flight = flightListVM.flights[index]
            flightListVM.deleteFlight(flight: flight)
            flightListVM.getAllFlights()
        }
    }

    var body: some View {
        List {
            ForEach(flightListVM.flights, id: \.id) { flight in
                NavigationLink(destination: FlightDetailView(flight: flight )) {
                    FlightCell(flight: flight)
                }
            }.onDelete(perform: deleteFlight)
        }
        .listStyle(PlainListStyle())
        .navigationTitle("Flights")
        .sheet(isPresented: $isPresented, onDismiss: {
            flightListVM.getAllFlights()
        }) {
            NewFlightView()
        }
        .onAppear {
            flightListVM.getAllFlights()
        }
    }
}

2. 进阶优化:自动监听CoreData数据变化

手动调用getAllFlights()不够优雅,可利用CoreData的监听机制,让ViewModel自动感知数据变化并更新列表,彻底摆脱手动刷新:

修改FlightListViewModel代码

import Combine
import CoreData

class FlightListViewModel: ObservableObject {
    @Published var flights = [FlightViewModel]()
    private var cancellables = Set<AnyCancellable>()

    init() {
        // 创建Flight实体的查询请求
        let fetchRequest: NSFetchRequest<Flight> = Flight.fetchRequest()
        // 按日期倒序排列(可选配置)
        fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Flight.date, ascending: false)]
        
        // 监听CoreData上下文的查询结果变化,自动更新列表
        CoreDataManager.shared.persistentContainer.viewContext
            .publisher(for: fetchRequest)
            .map { flights in
                flights.map(FlightViewModel.init)
            }
            .receive(on: DispatchQueue.main)
            .assign(to: \.flights, on: self)
            .store(in: &cancellables)
    }

    func deleteFlight(flight: FlightViewModel) {
        if let flight = CoreDataManager.shared.getFlightById(id: flight.id) {
            CoreDataManager.shared.deleteFlight(flight)
        }
    }

    // 不再需要getAllFlights()方法,数据变化时自动触发列表更新
}

修改后,无论是新增、删除还是修改Flight数据,列表都会自动刷新,无需手动调用刷新方法。


内容的提问来源于stack exchange,提问作者AVSoftware

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 01:18:14