Reputation: 122
I found this demo project that shows how to use clean swift with swiftU, so I tried to do something like this on my own. I came up with problem while using Core Data. As clean swift architecture only one source (appState in my case) can pass data to view. So I created injection container, it has interactor and appState. Container:
struct DIContainer: EnvironmentKey {
@ObservedObject var appState: AppState
let interactors: Interactors
init(appState: AppState, interactors: Interactors) {
self.appState = appState
self.interactors = interactors
}
class AppState: ObservableObject, Equatable {
var userData = UserData()
}
extension AppState {
class UserData: ObservableObject, Equatable {
@Published var places:[Place] = []
}
And I inject enviroment like this:
@Environment(\.injected) private var injected: DIContainer
And finally view that uses it:
var body: some View {
NavigationView {
ZStack {
List {
ForEach(injected.$appState.userData.places.wrappedValue){ place in
PlaceRow(place: place)
}
....
Problem is that even array is loade, view doesnt react to that. It refreshes only when i navigate to other view. Also, when I delete or add new elements to array, view has no changes. If you can give me some ideas it would be nice. I googled for 4 days, everything I find is not working for me.
Upvotes: 1
Views: 246
Reputation: 54426
If you're injecting the DIContainer
into your View
like this:
@Environment(\.injected) private var injected: DIContainer
remember that your View
will not refresh when the DIContainer
properties will change. You have to manually observe them.
You can try one of these solutions:
1) Subscribe to the AppState
properties' changes in .onReceive
:
@Environment(\.injected) private var injected: DIContainer
var body: some View {
NavigationView { ... }
.onReceive(injected.appState.userData.$places) { places in
// do something with places,
// eg. assign to a @State variable to be used in a `ForEach` loop...
}
}
2) Inject the UserData
directly as an @EnvironmentObject
:
@EnvironmentObject var userData: UserData
ContentView().environmentObject(container.appState.userData)
As the UserData
is an ObservableObject
it will change whenever any of its @Published
properties (eg. places
) is modified.
3) Subscribe to the AppState
/UserData
in the ViewModel
and observe the only the ViewModel
in your View
.
The more detailed explanation can be found in this version of the same demo project you linked in your question.
Upvotes: 1