emenegro
emenegro

Reputation: 6971

Forward transformed event from Observable directly to BehaviourSubject

I'm really really new to Rx and RxSwift and I'm trying to learn by reading and doing at the same time, so maybe this question makes you laugh. Please, excuse me in advance :P

I have this architecture:

MatchView -> MatchViewModel -> P2PSession -> MCSession+Rx

I've made a Reactive extension of MCSession to make session state changes an observable:

var didChangeState: Observable<(MCPeerID, MCSessionState)> {
    return RxMCSessionDelegateProxy.proxy(for: base).didChangeStateSubject.asObservable()
}

Then, I have another object, P2PSession, subscribed to that observable in order to transform the received event to emit it to a BehaviorSubject<MCPeerID?> to be observed by my MatchViewModel, that will transform it to emit to a Variable<String> to be shown in a label.

Maybe that chaining is totally ridiculous but here is the complete (but simplified) thing:

P2PSession

var connectedPeer: BehaviorSubject<MCPeerID?> = BehaviorSubject(value: nil)

mcSession.rx.didChangeState
    .subscribe(onNext: { self.connectedPeer.onNext($0.0) })
    .disposed(by: disposeBag)

MatchViewModel

var peerName = Variable("")

p2pSession.connectedPeer.asObservable()
    .map({ $0?.displayName ?? "None" })
    .subscribe(onNext: { self.peerName.value = $0 })
    .disposed(by: disposeBag)

MatchView

viewModel.peerName.asDriver()
    .drive(peerLabel.rx.text)
    .disposed(by: disposeBag)

It works, as a peer connects, a delegate method is called in the RxMCSessionDelegateProxy and data travels through the chain until it is shown in the label.

But I think that could be made way more elegant. Is it possible to forward a transformed event from an observable to a subject without making the subscription to the first observable to transform and inject the value to the subject/variable? (as I make in P2PSession). I don't know if I've explained myself correctly but I think that's possible with flatMap but I'm not getting it correctly, maybe I need the subscribe anyway and I'm trying to do stupid things.

Thank you so much, I need your help!

Upvotes: 1

Views: 1066

Answers (1)

Infinity James
Infinity James

Reputation: 4735

Expose the connected peer via an Observable, and the peer name through a Driver:

let connectedPeer: Observable<MCPeerID?>
connectedPeer = mcSession.rx.didChangeState.map { $0.0 }

let peerName: Driver<String>
peerName = p2pSession.connectedPeer.map { $0.displayName ?? "None" }.asDriver(onErrorJustReturn: "None")

viewModel.peerName.drive(peerLabel.rx.text).disposed(by: disposeBag)

Upvotes: 2

Related Questions