post Image
RxSwift 3.3.0で追加された3つのUnit(Single, Maybe, Completable)

RxSwift 3.3.0で3つのUnitが追加されました。

  • Single
  • Maybe
  • Completable

RxJavaにあったものが輸入された形のようです。

付属のPlaygroundに例が書かれていなかったので、ざっくりどんなものか確認してみました。
この記事は半分備忘録みたいなものになります。

追記

3.4.0で subscription closures (onSuccess, onError, onCompleted) が実装されました。
やっぱり欲しいよね。プルリク投げてくれたfreak4pcさんありがとう。

Add subscription closures for Single, Maybe and Completable (onSuccess, onError, onCompleted) by freak4pc · Pull Request #1175 · ReactiveX/RxSwift

概要

まず前提として、 ObservableCompleted あるいは Error が流れた時点でそれ以上何も流れなくなりますが、その2つが流れない限り Next は延々と流れてくる可能性があります。

それを踏まえて今回追加された3つのUnitについて見てみると、以下の表のようになります。

Single Maybe Completable
Success ×
Completed ×
Error

Success は 1回だけ流れる Next だと思って下さい。
そのSuccess が流れるのが SingleMaybe です。
MaybeSuccess が流れず、 Completed のみ流れてくる可能性があります。
Completable では Success は流れてきません。

それぞれつくって、実際にどんな風に使えるのか見ていきましょう。

Single

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Single<String>
    .create(subscribe: { (observer) -> Disposable in
        observer(.success("🐶"))
        observer(.success("🐱")) // ignored
        observer(.error(MyError.unknown)) // ignored
        return Disposables.create()
    })
    .do(onNext: { (value) in
        print("onNext")
    }, onError: { (error) in
        print("onError")
    }, onCompleted: {
        print("onCompleted")
    }, onSubscribe: {
        // subscribe前に実行される 
        print("onSubscribe")
    }, onSubscribed: {
        // subscribe後に実行される 
        print("onSubscribed")
    })
    .subscribe({ (result) in
        switch result {
        case .success(let value):
            print("success: \(value)")
        case .error(let value):
            print("error: \(value)")
        }
    })
    .disposed(by: disposeBag)

追記:3.4.0からは次のようにも書けます

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Single<String>
    .create(subscribe: { (observer) -> Disposable in
        observer(.success("🐶"))
        observer(.success("🐱")) // ignored
        observer(.error(MyError.unknown)) // ignored
        return Disposables.create()
    })
    .subscribe(onSuccess: { (value) in
        print("success: \(value)")
    }, onError: { (error) in
        print("error: \(error)")
    })
    .disposed(by: disposeBag)

Maybe

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Maybe<String>
    .create(subscribe: { (observer) -> Disposable in
        observer(.completed)
        observer(.success("🐶")) // ignored
        observer(.error(MyError.unknown)) // ignored
        return Disposables.create()
    })
    .subscribe({ (result: MaybeEvent<String>) in
        switch result {
        case .success(let value):
            print("success: \(value)")
        case .completed:
            print("complete")
        case .error(let error):
            print("error: \(error)")
        }
    })
    .disposed(by: disposeBag)

追記:3.4.0からは次のようにも書けます

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Maybe<String>
    .create(subscribe: { (observer) -> Disposable in
        observer(.completed)
        observer(.success("🐶")) // ignored
        observer(.error(MyError.unknown)) // ignored
        return Disposables.create()
    })
    .subscribe(onSuccess: { (value) in
        print("success: \(value)")
    }, onError: { (error) in
        print("error: \(error)")
    }, onCompleted: {
        print("complete")
    })
    .disposed(by: disposeBag)

Completable

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Completable
    .create(subscribe: { (observer) -> Disposable in
        observer(.error(MyError.unknown))
        observer(.completed) // ignored
        return Disposables.create()
    })
    .subscribe({ (result: CompletableEvent) in
        switch result {
        case .completed:
            print("complete")
        case .error(let value):
            print("error: \(value)")
        }
    })
    .disposed(by: disposeBag)

追記:3.4.0からは次のようにも書けます

let disposeBag = DisposeBag()

enum MyError: Error {
    case unknown
}

Completable
    .create(subscribe: { (observer) -> Disposable in
        observer(.error(MyError.unknown))
        observer(.completed) // ignored
        return Disposables.create()
    })
    .subscribe(onCompleted: { 
        print("complete")
    }, onError: { (error) in
        print("error: \(error)")
    })
    .disposed(by: disposeBag)

所感

今回追加されたUnitは使いたいシーンが結構ありそうです。
今まで Next が何回流れるか示したい場合はAppleDoc等で分かるようにしないといけませんでした。1回だけで良いのであれば、 SingleMaybe を使えば、ドキュメントに記載しなくても意図が明確になります。


『 Swift 』Article List