Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing Core Data FetchedResults<T> for previews in SwiftUI

I have a parent view which does a @FetchRequest and passes the FetchedResults<T> to a child view. Everything works, and the child view is able to parse through the FetchedResults. However, I can't figure out how to set up the data so that the child's Preview struct will work. What's the proper way to set up some constant data in Preview struct so that I can instantiate the child view and pass in FetchedResults<T>?

like image 490
andrw Avatar asked Apr 29 '20 05:04

andrw


1 Answers

As FetchedResults<T> is a RandomAccessCollection and swift array also is a RandomAccessCollection, here is possible solution.

Update: verified with Xcode 13.3 / iOS 15.4

struct ContentView: View {
    @Environment(\.managedObjectContext) var context
    @FetchRequest(entity: Person.entity(), sortDescriptors: [])
        var result: FetchedResults<Person>

    var body: some View {
        VStack(alignment: .leading) {
            Text("Persons").font(.title)
            PersonsView(results: result) // FetchedResults<Person> is a collection
        }
    }
}

// generalize PersonsView to depend just on collection
struct PersonsView<Results:RandomAccessCollection>: View where Results.Element == Person {
    let results: Results
    var body: some View {
        ForEach(results, id: \.self) { person in
            Text("Name: \(person.name ?? "<unknown>")")
        }
    }
}

// Tested with Xcode 11.4 / iOS 13.4
// DOES NOT WORK ANYMORE !!
// struct ChildView_Previews: PreviewProvider {
//    static var previews: some View {
//        PersonsView(results: [Person()]) // << use regular array //to test
//    }
}

Update: fixed & tested part for Xcode 12 / iSO 14 (due to crash of above PreviewProvider)

It appears entity now should be read & specified explicitly:

struct ChildView_Previews: PreviewProvider {
    static let entity = NSManagedObjectModel.mergedModel(from: nil)?.entitiesByName["Person"]

    static var previews: some View {
        let person = Person(entity: entity!, insertInto: nil)
        person.name = "Test Name"

        return PersonsView(results: [person])
    }
}

backup

like image 196
Asperi Avatar answered Sep 29 '22 02:09

Asperi