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.83k stars 709 forks source link

Question: navigate back programmatically #48

Closed claudius-kienle closed 3 years ago

claudius-kienle commented 3 years ago

First of all, thank you for the awesome architecture!

I encountered following problem, when trying to extend it with following scenario:

Supposing the CountryDetailsView has some kind of update button, e.g.:

func basicInfoSectionView(country: Country, details: Country.Details) -> some View {
    Section(header: Text("Basic Info")) {
        ...
        Button(action: viewModel.updateCountry) {
            Text("Update")
        }
    }
}

The CountryDetailsViewModel consists now of following function:

func updateCountry() {
    // do some update stuff
    container.appState[\.routing.countriesList].countryDetails = nil
}

So after 'updating' the country (in my case doing an api call), i want the detail view to pop. But doing so programmatically with the help of the appState doesn't work.

I tried changing the NavigationLink in CountriesList to work with isActive, since the selection version has knowingly some bugs (https://stackoverflow.com/questions/66128198/swiftui-list-selection-always-nil) but it's still not working.

The only way i've managed the view to pop is by injecting:

  @Environment(\.presentationMode) var presentationMode

into the view but then only the view can pop itself not the viewModel.

Do you have some idea how i could implement it the clean way?

pauluhn commented 3 years ago

I've been playing with this arch in two side projects and I've run into this as well.

For me, I'm not using MVVM variant, I opted for going with the redux-like one-way flow. So in my case, I would pass the details view a binding of the presentation flag set to true. When it was done, it would set that flag to false. That value propagates back to the parent who can then dismiss the child view.

The idea of manipulating state and letting the views react requires letting go of many event-based best practices.

But I will say that it is A LOT more fun working in SwiftUI + Combine than UIKit + RxSwift.