swiftcombine

Updating a @Published variable based on changes in an observed variable


I have an AppState that can be observed:

class AppState: ObservableObject {

    private init() {}
    static let shared = AppState()

    @Published fileprivate(set) var isLoggedIn = false

}

A View Model should decide which view to show based on the state (isLoggedIn):

class HostViewModel: ObservableObject, Identifiable {

    enum DisplayableContent {
        case welcome
        case navigationWrapper
    }

    @Published var containedView: DisplayableContent = AppState.shared.isLoggedIn ? .navigationWrapper : .welcome

}

In the end a HostView observes the containedView property and displays the correct view based on it.

My problem is that isLoggedIn is not being observed with the code above and I can't seem to figure out a way to do it. I'm quite sure that there is a simple way, but after 4 hours of trial & error I hope the community here can help me out.


Solution

  • Working solution:

    After two weeks of working with Combine I have now reworked my previous solution again (see edit history) and this is the best I could come up with now. It's still not exactly what I had in mind, because contained is not subscriber and publisher at the same time, but I think the AnyCancellable is always needed. If anyone knows a way to achieve my vision, please still let me know.

    class HostViewModel: ObservableObject, Identifiable {
    
        @Published var contained: DisplayableContent
    
        init() {
            self.contained = .welcome
            setupPipelines()
        }
    
        private func setupPipelines() {
            AppState.shared.$isLoggedIn
                .map { $0 ? DisplayableContent.mainContent : .welcome }
                .assign(to: &$contained)
        }
    
    }
    
    extension HostViewModel {
    
        enum DisplayableContent {
            case welcome
            case mainContent
        }
    
    }