odieatla
odieatla

Reputation: 1079

RxSwift - Chaining Observables and Singles

I need to call a sequences of function to get all the information I need for a notification. First subscribe which opens up the session, then queryNotification to listen on all the incoming notifications, and once a notification is received, need to call getNotificationAttrs with the notificationId returned in queryNotification, then call getAppAttributes with appIdentifier returned in getNotificationAttrs and I need the combined result of queryNotification, getNotificationAttrs and getAppAttributes. How the functions look like are below:

func subscribeNotification() -> Single<Info>
func queryNotification() -> Observable<Notification>
func getNotificationAttrs(uid: UInt32, attributes: [Attribute]) -> Single<NotificationAttributes>
func getAppAttributes(appIdentifier: String, attributes: [AppAttribute]) -> Single<NotificationAppAttributes>

The tricky part is that queryNotification returns Observable and both getNotificationAttrs and getAppAttributes return Single. What I have in mind of chaining them together is like:

subscribeNotification()
    .subscribe(onSuccess: { info in
        queryNotification()
            .flatMap({ notification in 
                return getNotificationAttributes(uid: notification.uid, attributes: [.appIdentifier, .content])
            })
            .flatMap({ notifAttrs
                return getAppAttributes(appIdentifier: notifAttrs.appIdentifier, attributes: [.displayName])
            })
            .subscribe {
                // have all the result from last two calls
            }
       })

Is this doable? Any direction is appreciated! Thanks!

Upvotes: 1

Views: 3796

Answers (1)

Daniel T.
Daniel T.

Reputation: 33967

The most obvious and IMHO correct solution is to promote your Single into an Observable. Also, I'm not a fan of the first subscribe where it is. You end up with an indentation pyramid.

I'm following your comments about needing the values from all of queryNotification(), getNotificationAttrs(did:attributes:) and getAppAttributes(appIdentifier:attributes:)...

let query = subscribeNotification()
    .asObservable()
    .flatMap { _ in queryNotification() }
    .share(replay: 1)

let attributes = query
    .flatMap { getNotificationAttrs(uid: $0.uid, attributes: [.appIdentifier, .content]) }
    .share(replay: 1)

let appAttributes = attributes
    .flatMap { getAppAttributes(appIdentifier: $0.appIdentifier, attributes: [.displayName]) }

Observable.zip(query, attributes, appAttributes)
    .subscribe(onNext: { (query, attributes, appAttributes) in

    })

The above will follow the steps you outlined and the subscribe will get called every time a new notification is emitted.

Also notice how the above reads quite a bit like synchronous code would (just with some extra wrapping.)

Upvotes: 4

Related Questions