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

SwiftUI中FetchRequest有10条数据却不显示列表内容的问题

问题:SwiftUI中@FetchRequest无法获取Core Data实体数据,列表显示为空

我在开发SwiftUI应用时遇到以下问题:在ServicesView中使用@FetchRequest获取Category实体数据,控制台通过Category.numberOfEntities()打印出有10条实体,但列表却显示为空(显示“Nothing here”)。

相关代码如下:

struct ServicesView: View {
    @FetchRequest(entity: Category.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Category.name, ascending: false)], animation: .easeIn) var results: FetchedResults<Category>

    var body: some View {
        List(results) { category in
            VStack(alignment: .leading, spacing: 3, content: {
                Text(category.name)
                    .font(.system(size: 12))
                    .foregroundColor(.white)
                Text("x\(category.services.count)")
            })
        }
        .overlay(
            Text(results.isEmpty ? "Nothing here" : "")
        )
        .onAppear {
            print("😋")
            print(Category.numberOfEntities())
        }
    }
}

控制台输出:

😋
10

我猜测问题在于未给视图分配@Environment的managedObjectContext,相关的计数逻辑代码如下:

extension NSManagedObjectContext {
    static func defaultContext() -> NSManagedObjectContext {
        CoreDataManager.shared.defaultContext!
    }
}


protocol Fetchable {
    associatedtype FetchableType: NSManagedObject = Self
    static func numberOfEntities() -> Int
}

extension Fetchable where Self: NSManagedObject {
    static var entityName: String {
        entity().name ?? ""
    }
    static func numberOfEntities() -> Int {
        let request = NSFetchRequest<FetchableType>(entityName: entityName)
        let context = NSManagedObjectContext.defaultContext()
        do {
            return try context.count(for: request)
        } catch let error as NSError {
            print("❌ Core Data Count Error \(error), \(error.userInfo)")
            return 0
        }
    }
}

请问如何在App入口的代码中给ServicesView分配managedObjectContext?相关入口代码如下:

@main
struct Watch_AppApp: App {
    var body: some Scene {
        WindowGroup {
                TabView {
                    TimerView()
                    ContentView()
                    ServicesView()  // how do I assign here managed object context?
                    Text("4th page")
                }
                .tabViewStyle(PageTabViewStyle())
                .onAppear(perform: loadData) //load data, fetch categories from cloudkit and save to core data, is is fetched and saved
            }
    }
}

解决方案

你的猜测正确,@FetchRequest默认从视图环境中读取managedObjectContext,如果没有注入,它使用的上下文和你保存数据的CoreDataManager.shared.defaultContext不是同一个,导致数据不同步。

1. 在App入口注入Managed Object Context

在App结构体中获取CoreDataManager的上下文,通过.environment(\.managedObjectContext, context)注入到整个视图层级:

修改后的App入口代码:

@main
struct Watch_AppApp: App {
    // 获取你的CoreDataManager提供的默认上下文
    private let managedContext = CoreDataManager.shared.defaultContext!
    
    var body: some Scene {
        WindowGroup {
            TabView {
                TimerView()
                ContentView()
                ServicesView()
                Text("4th page")
            }
            .tabViewStyle(PageTabViewStyle())
            // 将上下文注入到TabView及所有子视图的环境中
            .environment(\.managedObjectContext, managedContext)
            .onAppear(perform: loadData)
        }
    }
    
    func loadData() {
        // 你的数据加载逻辑:从CloudKit获取分类并保存到Core Data
    }
}

2. (可选)显式指定@FetchRequest的上下文

注入环境后,@FetchRequest会自动使用环境中的上下文,无需修改ServicesView。如果需要显式指定(多上下文场景),可以修改ServicesView的@FetchRequest:

struct ServicesView: View {
    @Environment(\.managedObjectContext) private var viewContext
    
    @FetchRequest(
        entity: Category.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Category.name, ascending: false)],
        animation: .easeIn,
        context: viewContext
    ) var results: FetchedResults<Category>
    
    // 剩余代码保持不变
}

核心原因说明

你的numberOfEntities()方法使用的是CoreDataManager.shared.defaultContext,而未注入环境时,@FetchRequest使用的是默认上下文(通常是NSPersistentContainer的viewContext,和你自定义的defaultContext不一致),导致两边读取的是不同的上下文实例,数据无法同步。注入环境后,整个视图树共享同一个上下文,@FetchRequest就能正确读取到保存的数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:20:46