如何在Widget中读取CoreData?调用fetch时报TimelineProviderContext无对应成员错误
错误原因
你代码里调用fetch方法的context是getTimeline方法传入的TimelineProviderContext类型参数,属于Widget时间线提供者的上下文对象,不是CoreData用来执行查询的NSManagedObjectContext实例,自然不存在fetch方法。
修复步骤
- 把执行查询的对象替换为你已经声明好的CoreData上下文
moc,也就是你之前定义的CoreDataStack.shared.managedObjectContext loadPersistentStores是异步执行的,你原本的代码在容器还没加载完存储的时候就执行查询,会拿不到数据,需要把查询逻辑放到loadPersistentStores的回调闭包里- 你原来的代码调用了两次
completion,一次是拿到查询结果就调用,一次是最后生成默认时间线再调用,会导致逻辑异常,需要把时间线生成的逻辑也放到查询完成的流程里,把查询到的数据传给SimpleEntry
修复后参考代码
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <替换为你的GroupID>)! let storeURL = containerURL.appendingPathComponent("DataModel.sqlite") let description = NSPersistentStoreDescription(url: storeURL) let container = NSPersistentContainer(name: "Entity") container.persistentStoreDescriptions = [description] container.loadPersistentStores { description, error in if let error = error { fatalError("Unable to load persistent stores: \(error)") } // 存储加载完成后再执行查询 let moc = CoreDataStack.shared.managedObjectContext let request = NSFetchRequest<Entity>(entityName: "Entity") request.predicate = NSPredicate(format: "attribute1 == %@", "test") var yourResult : [Entity]? do { // 这里换成moc调用fetch,不是传入的Widget context yourResult = try moc.fetch(request) } catch let error as NSError{ print(error.localizedDescription) } // 生成带查询结果的时间线,需要你先给SimpleEntry加个存储CoreData结果的属性,示例名为dataList var entries: [SimpleEntry] = [] let currentDate = Date() for hourOffset in 0 ..< 5 { let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! let entry = SimpleEntry(date: entryDate, configuration: configuration, dataList: yourResult ?? []) entries.append(entry) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } }
额外注意事项
- 确认你的
CoreDataStack已经配置了共享App Group的存储路径,和你上面创建的NSPersistentContainer指向同一个存储文件,避免主App和Widget读取的不是同一个数据库 - 确认Widget的Target已经勾选了App Group能力,和主App使用同一个Group ID
内容的提问来源于stack exchange,提问作者71873
相关产品推荐
相关产品推荐

