SwiftUI and data models (CoreData) - How to changing data?

Viewed 494

I'm extremely confused on how to use Core Data with SwiftUI. There are tons of articles about it but everyone's only showcasing crafted situations that work perfectly. Nobody's showing slightly more complicated stuff and I can't figure it out. I've been trying for two weeks. (I am able to code it in order to get it to simply work; However, I'm trying to find a good and pragmatic way and that's what I'm struggling with).

Here's an example:

struct CarView: View {
    @State var car: Car

    struct Car {
        let id: UUID = UUID()
        let name: String
        let price: Int
    }

    var body: some View {
        VStack {
            Text(car.name)
            Text("\(car.price)")
        }
    }
}


struct CarView_Previews: PreviewProvider {
    static var previews: some View {
        CarView(car: .init(name: "Tesla Model X", price: 42))
    }
}

This is a perfectly simple construct that's also easily testable and handleable because you can simply create a dummy Car instance to use XCode Previews, for instance.

But what happens if you want to add a data model to it that's pulling data from a database? Say you have a CarManagedObject NSManagedObject subclass. How would you connect that to our SwiftUI View?

You could simply replace the Car struct with CarManagedObject subclass because it conforms to ObservableObject. So something like this would work:

struct CarView: View {
    @ObservedObject var car: CarManagedObject
    ...
}

However, now we've tightly coupled the CarView with Core Data. You cannot use the view without it anymore. It's also a pain to create dummy data. So it would be better to keep using a Car struct that's independent of everything. This is also what Apple is doing in session 233 of WWDC 2019 starting at about minute 37: Session 23, WWDC 2019.

So you could do this:


struct Car {
    let id: UUID = UUID()
    let name: String
    let price: Int

    static func create(from: CarManagedObject) -> Car {
        ...
    }
}

This all works well until you have data that can change. I don't see a good way of keeping the struct updated when the underlying data changes. Also, we entirely lose the ability to pass Bindings down to subviews because the Car struct is not the actual data source. Changing it does not change the data model.

You could painfully set it up using Combine in both directions but that doesn't seem right. I'm sure SwiftUI is capable of doing this, I just don't see how.

Does anyone have an idea how to do this? Sorry if it's not entirely clear what I mean. I'm really confused. All this kind of breaks my head :D

1 Answers
Related