Search code examples
swiftrx-swift

RxSwift, how to use NotificationCenter more gently?


Got a IAP purchased notification, then I request the transaction from my server.

To download a song and play , if transaction OK.

I use RxSwift, The following code works, I want to improve it.

NotificationCenter.default.rx.notification( .purchase )
        .takeUntil(self.rx.deallocated)
        .map { (noti) -> String in
                return "Not care"
              // I want to optimize this step
        }.concat(self.transactionRequest())
        .flatMap{ self.downloadSong($0) }.subscribe(onNext: { downloaded in
            if downloaded{
                self.playMusic()
            }
        })
        .disposed(by: rx.disposeBag)


  func transactionRequest()  -> Observable<String> { // ... }

  func downloadSong(_ src: String) -> Observable<Bool> { // ...  }

I can not use like this

NotificationCenter.default.rx.notification( .purchase )
                   .takeUntil(self.rx.deallocated)
            .concat(self.transactionRequest())

because

Instance method 'concat' requires the types 'Notification' and 'String' be equivalent

So I add a boilerplate map

Any more proper operator, or custom operator?


Solution

  • The return type of the Observable that is feeding concat and the one that is passed to concat must be the same. I suggest you use flatMap instead. Also, you are capturing self all over the place which means memory issues.

    Here's how I would do it:

    NotificationCenter.default.rx.notification(.purchase)
        .flatMapLatest { [unowned self] _ in self.transactionRequest() }
        .flatMapLatest { [unowned self] in self.downloadSong($0) }
        .subscribe(onNext: { [unowned self] downloaded in
            if downloaded {
                self.playMusic()
            }
        })
        .disposed(by: rx.disposeBag)
    

    If you didn't put all your functions inside the class, you could get rid of the self. and not have to worry about capturing self.