SwiftUI构造器用@Environment变量初始化Core Data子上下文报self提前使用错误
问题原因
SwiftUI 的 @Environment 变量是在视图实例初始化完成之后才会被系统注入赋值的,init 构造器执行的阶段环境变量还没有完成注入,此时访问 managedObjectContext 就会触发 self 未完成初始化的错误。
解决方案
方案1:将主上下文作为构造器入参传入(推荐)
调用视图时直接把父视图已经获取到的主上下文作为参数传入,无需等待环境变量注入,改动最小逻辑最清晰:
struct CreatePlayerView: View { @State private var newPlayer: PlayerEntity private let childManagedObjectContext: NSManagedObjectContext // 按需保留环境变量即可,如果后续不需要用到也可以删掉 @Environment(\.managedObjectContext) private var managedObjectContext // 新增构造器入参接收主上下文 init(mainContext: NSManagedObjectContext) { childManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) childManagedObjectContext.parent = mainContext newPlayer = PlayerEntity(context: childManagedObjectContext) } var body: some View { EditPlayerViewDetail( player: $newPlayer, onDone: { player in try? childManagedObjectContext.save() // 子上下文保存后仅会同步到父主上下文,如需持久化到磁盘需要额外调用主上下文的save try? managedObjectContext.save() } ) } }
调用侧代码示例(父视图中已经持有环境注入的主上下文):
@Environment(\.managedObjectContext) var managedObjectContext // 调用时直接传参 CreatePlayerView(mainContext: managedObjectContext)
方案2:在onAppear生命周期中初始化
如果不想修改调用侧代码,可以把子上下文和临时实体声明为可选的@State变量,在视图渲染完成后的onAppear阶段初始化,此时环境变量已经注入完成:
struct CreatePlayerView: View { @State private var newPlayer: PlayerEntity? @State private var childManagedObjectContext: NSManagedObjectContext? @Environment(\.managedObjectContext) private var managedObjectContext init() {} var body: some View { Group { // 初始化完成后再渲染业务视图 if let newPlayer = newPlayer, let childContext = childManagedObjectContext { EditPlayerViewDetail( player: Binding($newPlayer)!, onDone: { player in try? childContext.save() try? managedObjectContext.save() } ) } else { // 初始化过程中显示占位加载态 ProgressView() } } .onAppear { // 此时环境变量已经注入,可以正常访问 let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) childContext.parent = managedObjectContext childManagedObjectContext = childContext newPlayer = PlayerEntity(context: childContext) } } }
注意事项
Core Data 子上下文执行 save 操作只会把变更同步到它的父上下文,不会直接写入持久化存储,如果需要把新增的数据持久化到本地,需要额外调用主上下文的 save 方法。
内容的提问来源于stack exchange,提问作者Shawn
相关产品推荐
相关产品推荐

