SwiftUI问题:将FetchedResults转为新数组触发StateObject警告
解决Core Data FetchResults转自定义数组为空及警告问题
问题说明
在SwiftUI中尝试从Core Data的FetchedResults<Item>提取数据创建自定义Item2数组时,在视图初始化方法里执行for item in items遍历操作,出现紫色警告:
Accessing StateObject's object without being installed on a View. This will create a new instance each time.
应用可正常运行,但生成的items2数组始终为空,需求是得到包含所有Core Data对象的新数组。数据模型为单个实体Item,包含text: String属性。
问题原因
@FetchRequest修饰的items是SwiftUI视图的状态依赖属性,在视图init方法执行阶段,视图尚未完成挂载,此时访问items无法获取到Core Data中的有效数据,导致数组为空,同时触发警告。- 直接声明的
var items2 = [Item2]()是普通存储属性,不会随items的变化自动更新,即使后续Core Data数据发生变更,数组也无法同步更新。
解决方案
将items2改为计算属性,每次访问时基于最新的items数据生成自定义数组,既解决初始化阶段无法获取数据的问题,也能自动同步Core Data数据的变化,同时移除init方法内的遍历逻辑。
修改后的完整代码
import SwiftUI import CoreData struct Item2: Identifiable { let id: UUID var text: String } struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Item.text, ascending: true)], animation: .default) private var items: FetchedResults<Item> // 改为计算属性,自动根据items生成最新数组 var items2: [Item2] { items.map { item in Item2( id: UUID(), text: item.text! ) } } var body: some View { NavigationView { List { ForEach(items2) { item2 in Text(item2.text) } } .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } ToolbarItem(placement: .destructiveAction){ Button(action: deleteAll) { Image(systemName: "trash") .foregroundColor(.red) } } } Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(context: viewContext) newItem.text = "List item" do { try viewContext.save() } catch { let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } } } private func deleteAll() { items.forEach(viewContext.delete) do { try viewContext.save() } catch { let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } }
补充说明
- 使用
map方法替代手动遍历,代码更简洁高效。 - 计算属性会在
items变化时自动重新计算,保证items2始终与Core Data数据同步。 - 移除
init方法后,避免了在视图未挂载时访问@FetchRequest属性,彻底消除警告。
内容的提问来源于stack exchange,提问作者mallow
相关产品推荐
相关产品推荐

