Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return/forward an observable inside Observable.create (RxSwift)

Tags:

swift

rx-swift

I wonder what's the correct way to "forward" (if that's the term) an observable to the observer of an observable I create.

Below there's an example.

My function performSomeActionAfterConfirmation displays an UIAlertController and returns a new observable. If "yes" is selected in the alert controller, I "forward" otherObservable() to the observer of the created observable. If "no" is selected, I just complete the observable.

I guess my code will work, since I've done something similar in RxJava, but in this case I get a warning in self?.otherObservable().subscribe(observer) saying that "Result of call to 'subscribe' is unused".

I guess I have to assign it to a DisposeBag, but I don't know how, since the bag is managed by the caller of performSomeActionAfterConfirmation. Maybe I should pass it as an argument to the function?

func performSomeActionAfterConfirmation() -> Observable<String> {

    return Observable<String>.create { [weak self] observer in

        let alertCtrl = UIAlertController(title: "perform action", message: "do it?", preferredStyle: .alert)

        // yes -> forward another observable
        alertCtrl.addAction(UIAlertAction(title: "yes", style: .default, handler: { _ in
            self?.otherObservable().subscribe(observer) // Result call is unused
        }))

        // no -> just complete this observable
        alertCtrl.addAction(UIAlertAction(title: "no", style: .default, handler: { _ in
            observer.onCompleted()
        }))

        self?.host?.present(alertCtrl, animated: true)

        return Disposables.create()
    }
}

func otherObservable() -> Observable<String> {
    return Observable.empty() // dummy code
}
like image 915
Ferran Maylinch Avatar asked Sep 03 '25 06:09

Ferran Maylinch


1 Answers

I believe yes, you can pass "outer" dispose bag into your function. It is needed because your observer will be subscribed to 2 sequences basically. One is the main one which can call only complete if "no" is selected, and one is inner one which can emit its own events.

But I believe that a bit easier way to achieve your intended behavior is to do make it step by step. What I mean is:

func performSomeActionAfterConfirmation() -> Observable<String> {

    return Observable<Void>.create { [weak self] observer in
        let alertCtrl = UIAlertController(title: "perform action", message: "do it?", preferredStyle: .alert)

        // yes -> emit one event and complete
        alertCtrl.addAction(UIAlertAction(title: "yes", style: .default, handler: { _ in
            observer.onNext()
            observer.onCompleted()
        }))

        // no -> just complete
        alertCtrl.addAction(UIAlertAction(title: "no", style: .default, handler: { _ in
            observer.onCompleted()
        }))

        self?.host?.present(alertCtrl, animated: true)
        return Disposables.create()
    }
    .flatMap { [weak self] _ -> Observable<String> in
        guard let `self` = self else { return .empty() }
        return self.otherObservable()
    }
}

func otherObservable() -> Observable<String> {
    return Observable.empty() // dummy code
}
like image 117
Nevs12 Avatar answered Sep 04 '25 23:09

Nevs12