StevenLambion / SwiftDux

Predictable state management for SwiftUI applications.
http://stevenlambion.github.io/SwiftDux
MIT License
153 stars 9 forks source link

Working with something like Core Data? #35

Closed hoopes closed 4 years ago

hoopes commented 4 years ago

Hi,

I was wondering if you had any guidance on how to use this library with something like Core Data? I'm interested in core data b/c i have a relatively nontrivial amount of data, and it seems to jive with core data nicely. (Also, I guess the latest version gives you icloud sync for free? I haven't really gotten there yet. Anyway...)

I can't seem to hold Core Data objects in the state (since they don't conform to StateType), so i'm creating extensions of the state objects to make queries against Core Data. Is that generally how you'd think Core Data would best be used?

For example:

extension ProjectState {

    var selectedProject: Project? {
        get {
            // selectedProjectId held in the swiftdux state
            guard let id = selectedProjectId else { return nil }

            let ctx = PersistenceManager.context
            let projFetch = PersistenceManager.projectFetchReq
            projFetch.predicate = NSPredicate(format: "id == %@", id as CVarArg)

            let projects = try! ctx.fetch(projFetch) as! [Project]

            return projects.count > 0 ? projects[0] : nil
        }
    }

In any case, I thought I might ask - thanks very much for your library, again. It's freakin great.

StevenLambion commented 4 years ago

I haven't used Core Data in quite a while, however, I am using sqlite on my current project to store data. When querying from either an API or sqlite, I do store the results in the state to be retrieved by the views. I follow the guidance from redux, which says that the state should only use simple, serializable types. The rule of thumb in Swift is that the state adheres to encodable. However, nothing is clear cut in all situations. (Such as with Core Data support.)

I'm wondering if you should take a look at the Swift-5.2 branch if you're able to use it with the latest Xcode beta. It has a lot of refinements from my own use of the library. One change is the removal of the StateType conformance on the store. The StateType is now present as a convienence rather than a requirement. You'll still need to adhere to Equatable to use your state with the ConnectableView API however.

hoopes commented 4 years ago

So, from the example above, you'd have some sort of serialize function on the Project object that converts the object to something that conforms to serializable types, and stores it on the state?

I will definitely try that branch - would it then let me store the real Project object in the state? All I'd have to do is override the == function that would check the id...

StevenLambion commented 4 years ago

With that branch, you should be able to use Project directly. You'll just need to adhere to Equatable.

For me, I typically separate the data layer from the application and UI layer to provide clear separation of concerns. As an example, in my current project I would query a list of records from sqlite in the data layer that would then be transform into a UI-friendly model when sent to the application layer. This model is what I'd insert into the state.

This isn't always necessary, and can actually add complexity and overhead to smaller projects and teams. Core Data also provides a lot of niceties that push developers to use its managed objects within the UI layer. I ran into this conundrum with Redux and GraphQL when using Facebook's Relay library. The compromise I made was to use Relay in the UI to handle the data model itself, but redux could handle any other UI or logical state.

hoopes commented 4 years ago

Hi, did you push your most recent changes? I'm getting these errors:

Screen Shot 2020-03-05 at 9 41 21 PM

I can get you line numbers if you need. Or I'm just doing something hilariously amateur-hour.

using the swift-5.2 branch in swift package manager

StevenLambion commented 4 years ago

That error makes me think it's getting compiled with the wrong version of Swift. Are you using Xcode 11.4 beta? Swift 5.2 adds a new "callAsFunction" mechanism to allow types, such as structs and protocols, to be called like a function.

hoopes commented 4 years ago

Sorry for the giant delay, I got this branch working in the latest xcode 11.4. I was having trouble with another library.

In any case, I think I'm sticking with the simple, serializable types in the view model, and using core data to persist the data - I'm still a swift beginner, and trying to understand all the protocols (esp decodable from a core data model) was beyond me for now.

The view model style feels pretty nice so far, and the reactivity of the app is really all i'm after, so if there's another minor layer in the way, so be it.

Thanks again, and sorry again for the delay on responding to this issue.