Search code examples
rx-swift

Convert PublishRelay to BehaviorRelay of optional Element


I have the following code in RxSwift 4.0-based project:

private var _myRelay = PublishRelay<MyData>()

var myRelay: Observable<MyData> {

    return _myRelay.asObservable()
}

Now I need to keep the last value (if any) in _myRelay, so I decided to convert it to BehaviorRelay:

private var _myRelay = BehaviorRelay<MyData?>(value: nil)

I want to keep public interface intact

var myRelay: Observable<MyData>

I mean I do not want to convert it to

var myRelay: Observable<MyData?>

The idea is not to "publish" initial value == nil to subscribers of myRelay, and start publishing only after some data appears. How can I do it? I am completely beginner in Rx, but I am sure there should be some elegant solution.


Solution

  • The simplest solution is to filter out the nils. If you were using 5.0 then you would do that with compactMap but since you said 4.0 that means you will need a filter and map:

    var myRelay: Observable<MyData> {
    
        return _myRelay.filter { $0 != nil }.map { $0! }.asObservable()
    }
    

    but you might actually be better off using a ReplaySubject instead of a Relay.

    private let _myRelay = ReplaySubject<MyData>.create(bufferSize: 1)
    
    var myRelay: Observable<MyData> {
    
        return _myRelay.asObservable()
    }
    

    That way, you don't have to deal with nils at all. (Also note, _myRelay should be a let not a var.)

    Doing the above will also allow you to emit a completed event when the observable goes out of scope (a relay doesn't allow that.)

    private let _myRelay = ReplaySubject<MyData>.create(bufferSize: 1)
    
    var myRelay: Observable<MyData> {
        return _myRelay.asObservable()
    }
    
    deinit {
        _myRelay.onCompleted()
    }