简体   繁体   中英

Recursive calls using RxSwift Observables

I am trying to do a recursive call using RxSwift Observables.

import RxSwift

func observeUntil(initialValue: Int) -> Observable<Int> {

    return Observable.deferred {
        .just(initialValue)
    }
    .do(onNext: {
        print("current item is", $0)
    })
        .flatMapLatest{ (item) -> Observable<Int> in
            if item < 5 {
                return Observable.just(item)
                    //                    .delay(.seconds(1), scheduler: MainScheduler.instance)
                    .flatMapLatest{observeUntil(initialValue: $0 + 1)}
            } else {
                return .just(item)
            }
    }
}
_ = observeUntil(initialValue: 0)
    .subscribe()

When I comment the delay in above code, the output comes correctly like below

current item is 0
current item is 1
current item is 2
current item is 3
current item is 4
current item is 5
Program ended with exit code: 0

with delay the code only outputs

current item is 0
Program ended with exit code: 0

Please help me to understand what happens when the delay is added.

The answer has to do with the environment you are executing this code in. The program calls the observeUntil(initialValue:) function and then exists as soon as that function returns.

Without the delay the function returns after the recursive code is all executed. With the delay the function returns when the delay starts.

Basically, your program ends in less than a second so only "0" is output.

_ = observeUntil(initialValue: 0).subscribe()

returns a Disposable if the reference is not saved, the observable will be destroyed after first onNext.

try:

let disposable = observeUntil(initialValue: 0).subscribe()

and to avoid memory leaks be sure to dispose it after you are done.

DispatchQueue.main.asyncAfter(.now() + 6) { // after 6 seconds
   disposable.dispose()
}

To clarify Daniel T.'s answer, as soon as your code

_ = observeUntil(initialValue: 0)
.subscribe()

goes out of scope, the subscription is disposed of, which is why you see it without the delay, but adding the delay will end up not executing the rest of the sequence until after it has been disposed of. The class which subscribes to the observable should have a DisposeBag which will retain the subscription when it goes out of scope.

// As an instance variable in your class, or some other place you want to retain the subscription
let disposeBag = DisposeBag()

// Where you subscribe
observeUntil(initialValue: 0)
.subscribe()
.disposed(by: myClass.disposeBag)

When the dispose bag goes out of scope, so will your subscription and it will be disposed of, terminating the sequence emitted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM