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