In the previous version of my app, I used this pattern for previews that depended on a NSManagedObjectContext:
With the delegate gone, I've swapped to this:
This works for previews some of the time. For example, I have this FilteredList:
This appears to work, but has issues if I don't explicitly create entities before rendering. Is there a better path I should take?
Code Block struct ContentView_Previews: PreviewProvider { static var previews: some View { let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext return ContentView().environment(\.managedObjectContext, managedObjectContext) } }
With the delegate gone, I've swapped to this:
Code Block class PreviewData { static var persistentContainer: NSPersistentContainer = { let container = NSPersistentCloudKitContainer(name: "Structure") container.loadPersistentStores(completionHandler: { _, error in if let error = error { fatalError("Unresolved error \(error)") } }) return container }() static var previewContext: NSManagedObjectContext { persistentContainer.viewContext }
This works for previews some of the time. For example, I have this FilteredList:
Code Block import CoreData import SwiftUI protocol StructureManagedObject { static var defaultSortDescriptors: [NSSortDescriptor] { get } } struct FilteredList<T: NSManagedObject & Identifiable & StructureManagedObject, Content: View>: View { let fetchRequest: FetchRequest<T> var results: FetchedResults<T> { fetchRequest.wrappedValue } let content: (T) -> Content init(sortDescriptors: [NSSortDescriptor] = [], predicate: NSPredicate? = nil, isActive: @escaping ((T) -> Bool) = { _ in false }, @ViewBuilder content: @escaping (T) -> Content) { var sortDescriptors = sortDescriptors if sortDescriptors.isEmpty { sortDescriptors = T.defaultSortDescriptors } fetchRequest = FetchRequest(entity: T.entity(), sortDescriptors: sortDescriptors, predicate: predicate) self.content = content } var body: some View { Group { if results.isEmpty { EmptyView() } else { ForEach(results) { r in self.content(r) } } } } } struct FilteredList_Previews: PreviewProvider { static var previews: some View { // This is required or preview will fail _ = Tag(context: PreviewData.previewContext, text: "#tagging") return VStack { FilteredList { (tag: Tag) in Text(tag.id) } }.wrappedPreview() } } class Tag: NSManagedObject { // ... }
This appears to work, but has issues if I don't explicitly create entities before rendering. Is there a better path I should take?
I was able to fix this by moving my data store into its own class and using the same thing for both the app and previews:
Code Block import CloudKit import CoreData import Foundation class DataStore { static let shared = DataStore() lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentCloudKitContainer(name: "Structure") container.loadPersistentStores(completionHandler: { _, error in if let error = error { fatalError("Unresolved error \(error)") } let context = container.viewContext context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy context.automaticallyMergesChangesFromParent = true // other setup here }) return container }() func saveContext() { let context = persistentContainer.viewContext if context.hasChanges { do { try context.save() } catch { fatalError("Unresolved error \(error)") } } } }