如何在Core Data中使用FetchedResults填充数组 SwiftUI MVVM场景问题
问题原因
@Environment、@FetchRequest是SwiftUI专用的属性包装器,仅能在View结构体中生效,在ObservableObject类中无法完成依赖注入、也无法执行查询逻辑,所以你拿到的artists1永远是空集合- 就算在View中使用
@FetchRequest,初始化阶段查询也尚未执行,此时直接访问结果为空,需要等待View的body渲染周期触发后才能拿到数据,不适合放到仓储类的初始化逻辑里
正确实现方案
你需要手动持有Core Data上下文,自行构造查询请求执行获取,同时监听Core Data的变更自动更新数据,修改后的完整代码如下:
import Foundation import SwiftUI import CoreData import Combine class SongRepository: ObservableObject, Identifiable { @Published var songs = [Song]() private let managedObjectContext: NSManagedObjectContext private var cancellables = Set<AnyCancellable>() // 初始化时传入Core Data上下文,不要用@Environment注入 init(context: NSManagedObjectContext) { self.managedObjectContext = context // 监听Core Data上下文的变更,数据改动后自动刷新 NotificationCenter.default.publisher( for: NSManagedObjectContext.didSaveObjectsNotification, object: managedObjectContext ) .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.loadData() } .store(in: &cancellables) // 首次加载数据 loadData() } func loadData() { // 手动构造FetchRequest执行查询,不要用@FetchRequest let fetchRequest: NSFetchRequest<Artists> = Artists.fetchRequest() fetchRequest.sortDescriptors = [] // 按需添加排序规则即可 do { let artists = try managedObjectContext.fetch(fetchRequest) // 转换为自定义的Song模型 songs = artists.map { artist in Song( album: artist.album, artistImage: artist.artistImage, artistname: artist.artistname ?? "", genre: artist.genre, songMp3: artist.songMp3, songname: artist.songname ) } } catch { print("Core Data查询失败: \(error)") } } }
使用方式
在你的SwiftUI App入口或者上层View中初始化仓储类,传入项目里已有的Core Data上下文即可,示例:
@main struct YourApp: App { // 这里用你项目中已有的持久化控制器实例即可 let persistenceController = PersistenceController.shared var body: some Scene { WindowGroup { ContentView() .environment(\.managedObjectContext, persistenceController.container.viewContext) // 将仓储类作为环境对象注入,所有子View都可以直接获取使用 .environmentObject(SongRepository(context: persistenceController.container.viewContext)) } } }
注意事项
- 原代码中对
artistname做了强制解包,建议替换为可选值默认值,避免Core Data中该字段为空时触发崩溃 - 如果需要添加查询筛选条件,直接给
fetchRequest.predicate赋值对应的NSPredicate即可 - 后续所有Core Data读写操作都可以封装在该仓储类中,对外仅暴露
@Published的songs数组,完全符合MVVM的单向数据流要求
内容的提问来源于stack exchange,提问作者multiverse
相关产品推荐
相关产品推荐

