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

SwiftUI应用中添加Core Data实体后刷新列表的问题

SwiftUI + Core Data Sheet关闭后列表不刷新的解决方案

临时解决办法:在Sheet的onDismiss中调用刷新方法

你可以在ContentView的Sheet绑定里添加onDismiss回调,手动调用vm.populateMovies()来刷新列表,这能快速解决当前问题:

.sheet(isPresented: $isPresented) {
    AddMovieView()
} onDismiss: {
    try? vm.populateMovies()
}

但这种手动同步的方式,并非Core Data的最优实践。

最优方案:利用Core Data的自动数据监听

Core Data本身支持数据变化的自动通知,无需手动触发刷新。你可以通过以下两种方式实现:

1. 在View中直接使用@FetchRequest

把电影列表的获取交给@FetchRequest,它会自动监听Core Data上下文的变化,数据更新时自动刷新视图:

struct ContentView: View {
    @State private var isPresented: Bool = false
    // 直接用@FetchRequest获取数据,可添加排序规则
    @FetchRequest(sortDescriptors: [SortDescriptor(\.title)]) var movies: FetchedResults<Movie>
    
    var body: some View {
        NavigationView {
            List(movies) { movie in
                Text(movie.title ?? "")
            }
            .navigationTitle("Movies")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Add Movie") {
                        isPresented = true
                    }
                }
            }
            .sheet(isPresented: $isPresented) {
                AddMovieView()
            }
        }
    }
}

2. 在ViewModel中监听上下文变化

如果希望业务逻辑集中在ViewModel里,可以通过监听NSManagedObjectContext.didSaveObjectsNotification来自动刷新数据:

class MovieListViewModel: ObservableObject {
    @Published var movies: [Movie] = []
    private let context: NSManagedObjectContext
    
    init(context: NSManagedObjectContext) {
        self.context = context
        fetchMovies()
        // 监听上下文保存事件,自动刷新列表
        NotificationCenter.default.addObserver(
            forName: NSManagedObjectContext.didSaveObjectsNotification,
            object: context,
            queue: .main
        ) { [weak self] _ in
            self?.fetchMovies()
        }
    }
    
    func fetchMovies() {
        let request: NSFetchRequest<Movie> = Movie.fetchRequest()
        do {
            movies = try context.fetch(request)
        } catch {
            print(error.localizedDescription)
        }
    }
}

同时要确保AddMovieViewModel使用同一个上下文(通过@Environment(\.managedObjectContext)注入),避免数据不同步:

class AddMovieViewModel: ObservableObject {
    @Published var title: String = ""
    private let context: NSManagedObjectContext
    
    init(context: NSManagedObjectContext) {
        self.context = context
    }
    
    func saveMovie() throws {
        let movie = Movie(context: context)
        movie.title = title
        try context.save()
    }
}

// 修改AddMovieView注入上下文
struct AddMovieView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.managedObjectContext) private var context
    @StateObject private var vm: AddMovieViewModel
    
    init() {
        _vm = StateObject(wrappedValue: AddMovieViewModel(context: context))
    }
    
    var body: some View {
        Form {
            TextField("Title", text: $vm.title)
            Button("Save") {
                do {
                    try vm.saveMovie()
                    dismiss()
                } catch {
                    print(error.localizedDescription)
                }
            }
        }
    }
}

这样修改后,添加新电影并保存上下文时,列表会自动刷新,无需手动调用刷新方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:10:25