[Xcode 12.4, Catalina 10.15.6, MacOS Project using SwiftUI and CoreData]
I'm working on an app to display some data I have. The business logic of the app is working fine, and now I've turned my attention to the UI.
In order to tidy up the UI, I would like to get the PreviewProvider
working for each view. I would also like the previews to display data I already have in the CoreData datastore.
After much frustration, I finally managed to get the preview to compile and display, however I'm not seeing any actual data in the preview. It appears that whilst the NSManagedObjectContext is there, the preview has not selected any entry to display.
How can I select, say the 3rd entry in my datastore to be displayed in the preview?
Below is my code for the view that includes the PreviewProvider
at the end (as normal) with some comments explaining it following.
import SwiftUI
struct DomainRow: View {
@Environment(\.managedObjectContext) var context
@ObservedObject var domain : DomainFiles
private var id : LocalizedStringKey {
get {
return LocalizedStringKey(String(Int(domain.id)))
}
}
var body: some View {
HStack (alignment: .center) {
Text(id)
Spacer()
VStack(alignment: .leading) {
Text(domain.name!)
.fontWeight(.bold)
.truncationMode(.tail)
.frame(minWidth: 20)
Text(domain.path!)
.font(.caption)
.opacity(0.625)
.truncationMode(.middle)
}
}
.padding(.vertical, 4)
}
}
#if DEBUG
struct DomainRow_Previews: PreviewProvider {
@Environment(\.managedObjectContext) var managedObjectContext
static var previews: some View {
let context = CoreDataStack.context
let domain = DomainFiles(context: context)
return DomainRow(domain: domain)
.environment(\.managedObjectContext, CoreDataStack.context)
}
}
#endif
DomainFiles
is a CoreData entity (with a couple thousand entries), each of which has several attributes that include id
, name
, and path
(to the file). CoreDataStack.context
is a reference to the struct shown below.
In order to get a static NSManagedObjectContext, as required by the PreviewProvider, I have added the following struct to my project, as per https://developer.apple.com/forums/thread/650269
import Foundation
import CoreData
struct CoreDataStack {
static var context: NSManagedObjectContext {
return persistentContainer.viewContext
}
static let containerName: String = "MyAppsDataStore"
static var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: containerName)
container.loadPersistentStores { (description, error) in
if let error = error {
print(error)
}
}
return container
}()
// Don't need to save anything in the preview.
// func saveContext() { ... }
}
I would, for example, like to pass in the entry with domain.id == 3
into the preview.
How can I do this?
(Thanks in advance for your attention.)
I worked out what was missing in my PreviewProvider
struct:
SQLite
to browse the datastore to find the one you want to see.struct EntriesView_Previews: PreviewProvider {
@Environment(\.managedObjectContext) var managedObjectContext
static var previews: some View {
let context = CoreDataStack.context
let domainFiles : [DomainFiles]
let requestDomainFiles : NSFetchRequest<DomainFiles> = DomainFiles.fetchRequest()
do {
domainFiles = try context.fetch(requestDomainFiles)
} catch {
let nserror = error as NSError
fatalError("Error \(nserror): \(nserror.userInfo)") // DO NOT DO THIS IN REAL CODE. PROVIDE FALLBACK
}
let domain = domainFiles[0]
return EntriesView(domain: domain)
.environment(\.managedObjectContext, CoreDataStack.context)
}
}