Swift非视图类访问CoreData报错:环境上下文未连接持久化存储协调器
解决Swift非视图类访问CoreData的问题
问题原因
你在readCoreData函数中每次都会创建一个全新的DataController实例,而NSPersistentContainer的loadPersistentStores是异步执行的——当你立刻调用上下文的fetch方法时,持久化存储可能还没完成加载,导致视图上下文没有关联到持久化存储协调器,从而触发报错:
Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x2805f04e0>
另外,重复创建DataController也违背了CoreData容器应该全局共享的设计原则,会导致数据不一致、资源浪费等问题。
解决方案1:使用单例共享DataController
让DataController成为单例,确保整个应用中只有一个实例,视图和非视图类都使用这个共享实例:
修改DataController代码:
import Foundation import CoreData class DataController: ObservableObject { // 全局共享的单例实例 static let shared = DataController() let container = NSPersistentContainer(name: "Model") // 私有初始化方法,禁止外部创建新实例 private init(){ container.loadPersistentStores { description, error in if let error = error{ print("Core Data failed to load \(error.localizedDescription)") } } } }
然后在非视图类的readCoreData中使用这个单例:
func readCoreData(){ var data = [ShoeEntity]() // 使用全局共享的DataController实例 let controller = DataController.shared let moc = controller.container.viewContext let request = ShoeEntity.fetchRequest() do{ data = try moc.fetch(request) print(data.count) }catch{ print("Fetch failed: \(error.localizedDescription)") } }
解决方案2:依赖注入(更灵活,适合测试)
通过初始化参数将DataController实例注入到非视图类中,确保它和视图使用的是同一个实例:
首先定义你的非视图类,在初始化时接收DataController:
class DataProcessor { private let dataController: DataController // 通过初始化注入DataController实例 init(dataController: DataController) { self.dataController = dataController } func readCoreData(){ var data = [ShoeEntity]() let moc = dataController.container.viewContext let request = ShoeEntity.fetchRequest() do{ data = try moc.fetch(request) print(data.count) }catch{ print("Fetch failed: \(error.localizedDescription)") } } }
然后在视图中,将环境中使用的DataController实例传递给这个非视图类:
struct ContentView: View { // 应用全局的DataController实例 @StateObject private var dataController = DataController() var body: some View { Text("Hello World") .environment(\.managedObjectContext, dataController.container.viewContext) .onAppear { // 传递和视图共享的DataController实例 let processor = DataProcessor(dataController: dataController) processor.readCoreData() } } }
内容的提问来源于stack exchange,提问作者Tobias Frydl
相关产品推荐
相关产品推荐

