RxSwiftCommunity / RxFlow

RxFlow is a navigation framework for iOS applications based on a Reactive Flow Coordinator pattern
MIT License
1.88k stars 117 forks source link

displayed is incorrect if subscription occurs when view is already on screen #186

Closed nflahavan closed 1 year ago

nflahavan commented 2 years ago

In the displayed variable created in Reactive+UIViewController.swift the initialState variable is set to false.

    /// Rx observable, triggered when the view appearance state changes
    var displayed: Observable<Bool> {
        let viewDidAppearObservable = self.sentMessage(#selector(Base.viewDidAppear)).map { _ in true }
        let viewDidDisappearObservable = self.sentMessage(#selector(Base.viewDidDisappear)).map { _ in false }
        // a UIViewController is at first not displayed
        let initialState = Observable.just(false)
        // future calls to viewDidAppear and viewDidDisappear will change the displayable state
        return initialState.concat(Observable<Bool>.merge(viewDidAppearObservable, viewDidDisappearObservable))
    }

Because of this initial state, if subscription to this observable occurs after a view is on screen the initial value will be false and will not change. This is a potential problem when contributing Stepper whose Presentable is a UIViewController.

One potential solution would be to change the initialState like so:

        // a UIViewController is at first displayed if it's view has a window
        // https://stackoverflow.com/a/2777460
        let initialState = Observable.just(base.viewIfLoaded?.window != nil)

I'm happy to PR this change if others think it would be useful.

mgray88 commented 1 year ago

Hi @nflahavan, I like the thought here. However since we are working with Observables, maybe it would be better to put that in a defer?

let initialState = Observable.defer { .just(base.viewIfLoaded?.window != nil) }

Feel free to open a PR!