Ios 在视图中插入实体时,SwiftUI预览无法处理核心数据

Ios 在视图中插入实体时,SwiftUI预览无法处理核心数据,ios,xcode,core-data,swiftui,Ios,Xcode,Core Data,Swiftui,几个月来,我一直在努力让预览在Xcode中工作,但核心数据 使用。我完全可以让预览对不包含 注射项目。但不是依赖于源实体的任何后续视图 假设我有一个主/细节项目,比如带有ContentView的SwiftUI项目 我的列表和ThingDetailView显示实体对象的详细信息 我为ContentView的预览创建了一个包装器: struct PreviewCoreDataWrapper<Content: View>: View { @Environment(\.managed

几个月来,我一直在努力让预览在Xcode中工作,但核心数据 使用。我完全可以让预览对不包含 注射项目。但不是依赖于源实体的任何后续视图

假设我有一个主/细节项目,比如带有ContentView的SwiftUI项目 我的列表和ThingDetailView显示实体对象的详细信息

我为ContentView的预览创建了一个包装器:

struct PreviewCoreDataWrapper<Content: View>: View {
    @Environment(\.managedObjectContext) private var viewContext
    let content: (NSManagedObjectContext) -> Content

    var body: some View {
        let managedObjectContext = viewContext
    
        let sampleThing = Thing(context: managedObjectContext)
        sampleThing.name = "Sample Name"
        sampleThing.comment = "Sample Comment"
        sampleThing.id = UUID()
        //more attributes

        return self.content(managedObjectContext)
    }

    init(@ViewBuilder content: @escaping (NSManagedObjectContext) -> Content) {
        self.content = content
    }
}
但在细节视图中,无论我尝试了什么,我都无法获得 预览工作。我已经尝试了几十种方法来满足这个要求

struct ThingDetailView_Previews: PreviewProvider {
    static var previews: some View {
        PreviewCoreDataWrapper { managedObjectContext in
            ThingDetailView(thing: sampleThing).environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
        }
    }
}
任何指导都将不胜感激。Xcode版本12.0(12A7208),iOS 14

ThingDetailView是相当标准的东西:

struct ThingDetailView: View {

    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedObjectContext) private var managedObjectContext

    var thing: Thing

    @State private var localName: String = ""
    @State private var localComment: String = ""
    //bunch more properties

    var body: some View {
    
        DispatchQueue.main.async {
            self.localName = self.thing.wrappedName
            self.localComment = self.thing.wrappedComment
            //buch more properties
        }//dispatch
        DispatchQueue.main.async {
            if !showEditView {
            localNewUIImage = UIImage(data: thing.tImage)
            }
        }
    
        //you need this to allow the TextEditor background to be changed
        UITextView.appearance().backgroundColor = .clear

        return ScrollView(.vertical, showsIndicators: false) {
            VStack(alignment: .center, spacing: 20) {
            
                //this is for an image
                if !showEditView {
                ThingHeaderView(thing: thing)
                } else {
                    NewPhotoView(myImage: $localMyImage, newUIImage: $localNewUIImage, disableSaveButton: $localDisableSaveButton)
                }
            
                VStack(alignment: .leading, spacing: 10) {
                    Group {//group 1
                        //MARK: name
                        VStack (alignment: .leading) {
                            if !showEditView {
                                Text("\(thing.wrappedName)")
                                    .frame(maxWidth: .infinity, alignment: .leading)
                                    .padding(.vertical, 5)
                                    .textFieldStyle(RoundedBorderTextFieldStyle())
                                    .font(.system(size: 22, weight: .bold, design: .default))
                                    .foregroundColor(Color("CardBlue"))
                            } else {
                                TextField("tf name", text: self.$localName)
                                    .modifier(TextFieldSetup())
                            }
                        }//name v
                    
                        //MARK: comment
                        VStack (alignment: .leading) {
                            if !showEditView {
                                Text("\(thing.wrappedComment)")
                                    .frame(maxWidth: .infinity, alignment: .leading)
                                    .padding(.vertical, 5)
                                    .textFieldStyle(RoundedBorderTextFieldStyle())
                                    .font(.headline)
                            } else {
                                TextEditor(text: self.$localComment)
                                    .modifier(TextEditorSetup())
                            }
                        }//comment v
                        //bunch more TextFields and TextEditors
                    }//group 1
                }//inner v
                .padding(.horizontal, 20)
                .frame(maxWidth: 640, alignment: .center)
            }//outer v
        
            //seems like a title is needed to remofe large space at top - then hide
            .navigationBarTitle(thing.wrappedName, displayMode: .inline)
            //.navigationBarHidden(true)
            .navigationBarBackButtonHidden(showEditView)
            .navigationBarItems(
            
                leading:
                    Button(action: {
                        if showEditView {
                            self.showEditView = false
                        }
                    }) {
                        Text(showEditView ? "Cancel" : "")
                            .font(.system(size: 20))
                    },
                trailing:
                    Button(action: {
                        if !showEditView {
                            print("showEditView is \(showEditView)")
                            self.showEditView = true
                        } else {
                            self.saveEditedRecord()
                            self.showEditView = false
                        }
                    }) {
                        Image(systemName: self.showEditView ? "square.and.arrow.down.fill" : "square.and.pencil")
                            .font(.system(size: 25))
                            .frame(width: 60, height: 60)
                    }//images
                    .disabled(self.localDisableSaveButton)
            )//nav bar item
        }//scroll
        .navigationViewStyle(StackNavigationViewStyle())
    }//body

    func saveEditedRecord() {
        print("...and you are in the save function...")
        let context = self.managedObjectContext
        thing.id = UUID()
        //all the rest and 
        //standard Core Data save
    }//save record
}//struct thing detail view
还有HeaderView:

struct ThingHeaderView: View {

    @Environment(\.horizontalSizeClass) var sizeClass
    @State private var isAnimatingImage: Bool = false

    var thing: Thing

    var body: some View {
    
        let sc = sizeClass == .compact
    
        return ZStack {
        
            if UIImage(data: thing.tImage) != nil {
                Image(uiImage: UIImage(data: thing.tImage)!)
                    .resizable()
                    .renderingMode(.original)
                    .aspectRatio(contentMode: .fit)
                    .cornerRadius(10)
                    .shadow(color: (Color.black.opacity(0.5)), radius: 8, x: 10, y: 10)
                    .padding(sc ? 6 : 10)
            } else {
                Image(systemName: "camera.circle.fill")
                    .resizable()
                    .frame(width: 60, height: 60, alignment: .center)
            }
        }
        .onAppear {
            withAnimation(.easeOut(duration: 0.5)) {
                isAnimatingImage = true
            }
        }
    }
}

我一直在预览中处理核心数据的方法不是使用“PreviewCoreDataWrapper”,而是在将视图返回预览之前定义我的viewContext并在预览中添加属性

struct ThingDetailView\u预览:PreviewProvider{
静态变量viewContext=PersistenceController.preview.container.viewContext
静态var预览:一些视图{
让sampleThing=Thing(上下文:viewContext)
sampleThing.name=“样本名称”
sampleThing.comment=“示例注释”
sampleThing.id=UUID()
//更多属性
返回ThingDetailView(thing:sampleThing).environment(\.managedObjectContext,viewContext)
}
}

这通常对我有用。祝你好运

你能给我看一下细节视图代码吗?在你的上一张快照中,
sampleThing
是什么?我在上面添加了。sampleThing什么都不是-唯一的目的是确定Xcode希望传递一个东西。谢谢您的想法。实际上我已经尝试过了,但是我收到了错误:“实例成员‘viewContext’不能用于类型‘ThingDetailView_Previews’”。在线:let sampleThing=Thing(context:viewContext)对不起,我忘了,视图上下文需要是静态的,因为预览是静态的@User2698617,它确实消除了上面提到的错误,但是预览仍然没有运行。我想我需要放弃预览工具,继续使用它。
struct ThingHeaderView: View {

    @Environment(\.horizontalSizeClass) var sizeClass
    @State private var isAnimatingImage: Bool = false

    var thing: Thing

    var body: some View {
    
        let sc = sizeClass == .compact
    
        return ZStack {
        
            if UIImage(data: thing.tImage) != nil {
                Image(uiImage: UIImage(data: thing.tImage)!)
                    .resizable()
                    .renderingMode(.original)
                    .aspectRatio(contentMode: .fit)
                    .cornerRadius(10)
                    .shadow(color: (Color.black.opacity(0.5)), radius: 8, x: 10, y: 10)
                    .padding(sc ? 6 : 10)
            } else {
                Image(systemName: "camera.circle.fill")
                    .resizable()
                    .frame(width: 60, height: 60, alignment: .center)
            }
        }
        .onAppear {
            withAnimation(.easeOut(duration: 0.5)) {
                isAnimatingImage = true
            }
        }
    }
}