在视图中注入实体时,SwiftUI预览不适用于核心数据

时间:2020-09-21 00:51:25

标签: ios xcode core-data swiftui

几个月来我一直很沮丧,试图在Core Data上使用Xcode进行预览 用来。我绝对可以对不包含预览的视图进行预览 注入的物品。但是没有依赖于源实体的任何后续视图。

假设我有一个类似Master / detail的SwiftUI项目,其中ContentView包含 我的列表和ThingDetailView显示了实体Thing的详细信息。

我为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
    }
}

然后在ContentView中预览此作品。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
    
        PreviewCoreDataWrapper { managedObjectContext in
            ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
        }
    }
}

但是在详细视图中,无论我尝试了什么,我都无法 预览工作。我尝试了多种方法来满足注入的Thing呼叫。

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

还有ThingHeaderView:

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
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

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

struct ThingDetailView_Previews: PreviewProvider {

    static var viewContext = PersistenceController.preview.container.viewContext

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

        return ThingDetailView(thing: sampleThing).environment(\.managedObjectContext, viewContext)
    }
}

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