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
相关产品推荐
相关产品推荐

