SwiftUI 预览画布和核心数据

Vic*_*Sea 22 core-data swiftui

预览画布正在崩溃,但在模拟器中一切正常。我假设它与@ObservedObject 和@Fetchrequest 相关...

在此处尝试使用 CoreData 预览 ContentView 的解决方案

不起作用

 import SwiftUI
 import CoreData

struct TemplateEditor: View {

@Environment(\.managedObjectContext) var managedObjectContext

@FetchRequest(
    entity: GlobalPlaceholders.entity(),
    sortDescriptors: [
        NSSortDescriptor(keyPath: \GlobalPlaceholders.category, ascending: false),
    ]
) var placeholders: FetchedResults<GlobalPlaceholders>


@ObservedObject var documentTemplate: Templates
@State private var documentTemplateDraft = DocumentTemplateDraft()
@Binding var editing: Bool


var body: some View {

    VStack(){
        HStack(){
            cancelButton
            Spacer()
            saveButton
        }.padding()
        addButton
        ForEach(placeholders)  {placeholder in
            Text(placeholder.name)
        }
        TextField("Title", text: $documentTemplateDraft.title)

        TextField("Body", text: $documentTemplateDraft.body)
            .padding()
            .frame(width: 100, height:400)
        Spacer()
    }

...




}
struct TemplateEditor_Previews: PreviewProvider {
    static var previews: some View {

    let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Templates")
    request.sortDescriptors = [NSSortDescriptor(keyPath: \Templates.created, ascending: false)]
    let documentTemplate = try! managedObjectContext.fetch(request).first as! Templates


    return TemplateEditor(documentTemplate: documentTemplate, editing: .constant(true)).environment(\.managedObjectContext, managedObjectContext).environmentObject(documentTemplate)

    }
}

Run Code Online (Sandbox Code Playgroud)

预计生成预览

小智 36

如果没有数据,我不确定您的 try 行是否有效。

let documentTemplate = try! managedObjectContext.fetch(request).first as! Templates
Run Code Online (Sandbox Code Playgroud)

为了让我的工作,我创建了一个测试项目来使用。像这样:

struct DetailView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
//Test data
        let newEvent = Event.init(context: context)
        newEvent.timestamp = Date()
        return DetailView(event: newEvent).environment(\.managedObjectContext, context)
    }
}
Run Code Online (Sandbox Code Playgroud)

我还注意到我需要在托管 CoreData 视图的早期 tabView 中使用 .environment(.managedObjectContext, context) 代码,否则预览将失败。

  • 上述问题已经以多种不同的方式提出和回答。这是唯一有效的答案!问题的本质是预览似乎从它自己的(空的!)持久存储开始,因此您必须以某种方式用足够的对象填充该存储以使所有预览都能工作。我创建了一个类函数,如果数据库为空,它会使用示例对象填充数据库。对于模型中的每个实体,我还创建了一个类函数,它将返回这些示例对象之一,以根据正在预览的特定视图的需要作为参数传递。 (2认同)

Tra*_*app 13

通过替换默认的 ContentView_Previews 结构,这个答案似乎在我最近的项目中有效,尽管其他人质疑它是否提取持久数据。归功于@ShadowDES - 在 Xcode Beta 7 的 Master/Detail 模板项目中

我可以使用 Canvas(XCode 版本 11.3 (11C29))对任何内容进行 CRUD,并且它似乎运行完美。

    #if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        return ContentView().environment(\.managedObjectContext, context)
    }
}
#endif
Run Code Online (Sandbox Code Playgroud)

添加值,标记优先级

滑动删除

已删除!


小智 5

什么对我有用:

我在持久性控制器的预览属性中创建了我的所有示例数据,使用以下设置启动项目时由 Xcode 生成的模板构建:界面 - SwiftUI,生命周期 - SwiftUI 应用程序,使用核心数据,在 CloudKit 中托管。我在这里发布了模板:

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext

        // ** Prepare all sample data for previews here ** //

        for _ in 0..<10 {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()
        }
        do {
            try viewContext.save()
        } catch {
            // handle error for production
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentCloudKitContainer

    init(inMemory: Bool = false) {
        container = NSPersistentCloudKitContainer(name: "SwiftUISwiftAppCoreDataCloudKit")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // handle error for production
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的预览中,我将持久性控制器注入到预览环境中,对于我的视图参数,我在预览视图上下文中使用了registeredObjects.first(where:) 方法来拉取所需类型的第一个对象:

struct MyView_Previews: PreviewProvider {
    static var previews: some View {
        MyView(item: PersistenceController.preview.container.viewContext.registeredObjects.first(where: { $0 is Item }) as! Item)
            .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}
Run Code Online (Sandbox Code Playgroud)


Keo*_*oni 0

一种选择是不在预览中使用核心数据。这对于查看我正在构建的 UI 很有帮助,但我仍然需要使用模拟器来测试功能。

#if !DEBUG
// Core Data related code e.g. @FetchRequest
#endif
Run Code Online (Sandbox Code Playgroud)

Previewing ContentView with CoreData中的建议对我有用,Xcode 版本 11.0 (11A419c) Mac OS 10.15 Beta (19A558d)。我的崩溃日志显示索引错误,

*** 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArray0 objectAtIndex:]:索引 0 超出空 NSArray 的范围”

因为那里没有数据,所以我必须处理这个独特的“预览”案例,这使得事情正常进行。