nalexn / clean-architecture-swiftui

SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.
MIT License
5.57k stars 671 forks source link

Question: UserDefaults #31

Closed mnightingale closed 3 years ago

mnightingale commented 4 years ago

How would you deal with UserDefaults?, usually I'd use an ObservableObject. But would it be preferable for the status of preferences to be in the store?

I've tried adding an interactor that has UserDefaults backed properties, but then they aren't bindable directly I guess it would have to work like routing? Interactor => [Subscribes to UserDefaults changes and pushed to Store] Then you'd need something like routingBinding but sending changes via the interactor?

Based on #30 for convenience would you just use a ObservableObject? and if so would you create an instance per view rather than storing it in EnvironmentObjects?

nalexn commented 4 years ago

Although UserDefaults is pretty simple and can be accessed synchronously, it's still a data gateway, just like a local database or a web server. Thus, it deserves its own Repository that would abstract away the access details. This would make it easier to evolve the project when you decide to migrate the values to a database or Keychain, share the values within the App Group, or reorganize the way data is stored in that Key-Value storage.

UI should not know the persistence layer details, it can only access AppState and Interactors, so it wouldn't know you're using UserDefaults or something else (which is good).

To me it seems logical to use AppState as the access point. When the app launches it can read the UserDefaults and load the values to the AppState, making it accessible for the UI.

When it comes to changing the value, one of your Interactors can provide an API for that, and under the hood, it'd use Repository for storing the value plus updating the value in the AppState.

nalexn commented 4 years ago

SwiftUI 2.0 update: Apple has introduced @AppStorage property wrapper, which introduces observable UserDefaults right into UI.

This aligns perfectly with the concept of SwiftUI - super-quick prototyping and development, a-la "move fast and break things". This is the spirit of SwiftUI.

Maybe I'm thinking mostly from the perspective of building large scale production apps on UIKit - so I'm not really buying this tight integration, but for the purpose of fast development - this is ideal.