预览画布崩溃,但是在模拟器中一切正常。我假设它与@ObservedObject和@Fetchrequest有关...
此处Previewing ContentView with CoreData的尝试解决方案
不起作用
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)
}
}
预期生成预览
答案 0 :(得分: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)")
}
})
}
}
在我的预览中,我将持久性控制器注入到预览环境中,对于我的视图参数,我使用 preview viewContext 上的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)
}
}
答案 1 :(得分:4)
我不确定如果没有数据,您的try线是否可以工作。
let documentTemplate = try! managedObjectContext.fetch(request).first as! Templates
为了使我的工作正常,我创建了一个要使用的测试项目。像这样:
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)
}
}
我还注意到,在托管CoreData视图的更早版本的tabView中,我需要.environment(.managedObjectContext,context)代码。否则预览将失败。
答案 2 :(得分:1)
一种选择是不在预览中使用CoreData。这对查看我正在构建的UI很有帮助,但是我仍然需要使用Simulator来测试功能。
#if !DEBUG
// CoreData related code e.g. @FetchRequest
#endif
Previewing ContentView with CoreData中的建议对我来说是XCode 11.0版(11A419c)Mac OS 10.15 Beta(19A558d)。我的崩溃日志显示索引错误,
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'
因为那里没有数据,所以我不得不处理这个独特的“预览”案例,并且使事情正常进行。
答案 3 :(得分:1)
这个答案似乎可以通过替换默认的ContentView_Previews结构在我最近的项目中使用,尽管其他人对此表示怀疑是否会提取持久数据。感谢@ShadowDES-在Xcode Beta 7的Master / Detail模板项目中
我可以使用Canvas(XCode版本11.3(11C29))对任何内容进行增删改查,而且它似乎可以完美运行。
#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
答案 4 :(得分:1)
使用App
模板的SwiftUI 2应用程序
我也遇到了预览崩溃,其他解决方案都不适合我。
我所做的不是以下内容:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
return ContentView()
.environment(
\.managedObjectContext,
CoreDataManager.context
)
}
}
我用以下方法修复了它:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = CoreDataManager.context
/* Optional sample data can be inserted here */
return ContentView()
.environment(
\.managedObjectContext,
context
)
}
}
CoreDataManager
在哪里:
enum CoreDataManager {
static var context: NSManagedObjectContext {
persistentContainer.viewContext
}
static let persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "MyContainerName")
container.loadPersistentStores { description, error in
guard let error = error else { return }
fatalError("Core Data error: '\(error.localizedDescription)'.")
}
return container
}()
}
不确定为什么这样做有帮助,但是现在可以正常使用了。此外,您可以将示例数据添加到我已标记为注释的context
上。
答案 5 :(得分:1)
这是我的解决方法。
我不想在视图中使用CoreData。我想要MVVM样式。 因此,您需要模拟Core数据以在Canvas视图中显示。
这是一个示例:
// View
struct MyView: View {
@ObservedObject var viewModel: PreviewViewModel
}
// View Model
final class MyViewModel: ObservableObject {
@Published var repository: RepositoryProtocol // CoreData
}
// Repository
protocol RepositoryProtocol { }
class Repository: RepositoryProtocol { ... }
class MockRepository: RepositoryProtocol { ... } // Create a Mock
// Init of your view
// If Canvas use mock
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
repository = MockRepository()
// else App use Repository
} else {
repository = Repository.shared
}
let viewModel = MyViewModel(repository:repository)
MyViewModel(viewModel: viewModel)
答案 6 :(得分:0)
因此,如果您在预览的//event to open the create customer form
private void OpenCreateCustomerForm(){
//first, create an instance of the form
frmCreateCustomer frm = new frmCreateCustomer();
/*second, add the function DataFill() to the FormClosed event of the create customer form, so everytime you close it, the MainForms datagridview will get updated*/
frm.FormClosed += new FormClosedEventHandler((object s, FormClosedEventArgs f) => { DataFill();});
//finally, show the create customer form
frm.ShowDialog();
};
处理程序中放入一些代码,它将在启动时运行。输入时它甚至可以实时更新!
onAppear
请注意,我已将struct TemplateEditor_Previews: PreviewProvider {
static var previews: some View {
TemplateEditor().environment(\.managedObjectContext, AppDelegate.viewContext).onAppear {
let entity = GlobalPlaceholders(context: AppDelegate.viewContext)
entity.name = "abc123"
// Or create more, if you need more example data
try! AppDelegate.viewContext.save()
}
}
}
封装在viewContext
上的静态方法中,以使访问变得更简洁,更容易记住:
AppDelegate
答案 7 :(得分:0)
它崩溃了,因为它在 PersistenceController
中被指示:
struct PersistenceController {
...
static var preview: PersistenceController = {
...
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
...
}
所以实际原因可以在崩溃报告中看到。实际上,XCode 12.4 显示了有关检查崩溃报告的警告;但是,对于像我这样的 Web 开发新手来说,该报告太冗长了。因此我花了一段时间才找出问题所在,所以我希望这可以为其他人节省一些时间。
...我的问题是在填充核心数据模型进行预览时没有设置必需的属性。
答案 8 :(得分:0)
这对我有用。在 AppDelegate 中创建一个不同的预览上下文并用对象填充它。
lazy var persistentContainerPreview: NSPersistentContainer = {
let persistentContainer = NSPersistentContainer(name: "MyModel")
persistentContainer.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
}
})
let didCreateSampleData = UserDefaults.standard.bool(forKey: "didCreateSampleData")
if !didCreateSampleData {
let context = persistentContainer.viewContext
let recipe = Recipe(context: context)
recipe.title = "Soup 2"
recipe.difficultyName = "NOT TOO TRICKY"
recipe.difficultyValue = 1
recipe.heroImage = "dsfsdf"
recipe.ingredients = "meat"
recipe.method = "sdcsdsd"
recipe.published = Date()
recipe.recipeId = 1
recipe.servings = 4
recipe.tags = "sdfs"
recipe.totalTime = 100
recipe.totalTimeFormatted = "Less than 2 hours"
try! context.save()
}
return persistentContainer
}()
然后在您的预览中。
struct RecipeView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainerPreview.viewContext
let recipe = try! context.fetch(Recipe.fetchRequest()).first as! Recipe
RecipeView(recipe: recipe).environment(\.managedObjectContext, context)
}
}
答案 9 :(得分:0)
问题是您需要找出导致崩溃的线路。
由于画布没有显示详细错误,使用 OSLog 和 Console.app 进行调试将是一个可能的解决方案。
例如:
import os.log
struct YourView_Previews: PreviewProvider {
static var previews: some View {
os_log("[DEBUG]-\(#function)---1--")
let moc = PersistenceController.preview.container.viewContext
os_log("[DEBUG]-\(#function)---2--")
let item = Item.previewData(context: moc)
os_log("[DEBUG]-\(#function)---3--")
return YourView(item: item, now: Date())
.environment(\.managedObjectContext, moc)
}
}
记得使用过滤器来更好地捕捉来自控制台的调试消息。
在找出导致崩溃的线路后,您可以进一步查看线路并继续该过程,直到找到罪魁祸首。
(就我而言,我忘记将 UUID 添加到导致画布崩溃的预览数据中。)