Swift
wwdc2019

Combineフレームワーク と RxSwift その1


Combineフレームワークとは

先日のWWDCで発表されたSwiftUIのインパクトはすごかったですが、それと一緒に導入されたCombineフレームワークも個人的には衝撃でした!

Appleの更新ページでは下記のように説明されています。


The Combine framework provides a declarative Swift API for processing values over time. These values can represent user interface events, network responses, scheduled events, and many other kinds of asynchronous data. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.



  • UIイベント、ネットワーク応答、スケジュールされたイベント、および他の多くの種類の非同期データを表せる

  • 時間の経過とともに変化する可能性のある値を公開するPublishersを提供

  • Subscriberは、Publisherから値を受け取ることが可能

これって、RxSwiftみたいなフレームワークなのかなと思ってAPIリファレンスを覗いたところ、想像以上にRxSwiftでした!

大枠ではRxSwiftのネイティブ実装といっても良いのですが、やはり細かい違いはありますので気がついたところを見ていきます。


Combineのクラスは、RxSwftのクラスで説明すると大体こんな感じです。

Combine
RxSwift

Publisher
--

Subscriber
--

PassthroughSubject
PublishSubject

CurrentValueSubject
BehaviorSubject
Variable

AnyPublisher
Observable

AppleのリファレンスはCombineの概要を説明するのに、Publisher、Subscriber という名前を出しているのですが、この2つはProtocolなので、実際のコードではどの様に書けばいいのか迷子になりがちですが、Subjectを中心にするのが正解です。

ということで、PassthroughSubject から入っていきましょう!


let pSubject = PassthroughSubject<Int,Never>()
//Rxではbind関数だが、Combineではsink関数
pSubject.sink { value in
print(value)
}
//Rxのオペレータは大体あります!!!
pSubject.filter{$0.isMultiple(of: 2)}
.map { $0 + 10 }
.sink { print($0) }
//onNextじゃなくてsendで値を流す
pSubject.send(100)

CombineのSubjectはエラーを流すことができますが、RxではSubjectはエラーを流さない事を保証しています。ココが大きな違いですね。

let subject = PassthroughSubject<Int,NSError>() //このsubjectはNSErrorを流す事がある

subject.send(completion: .finished) // RxのonCompleteにあたる
subject.send(completion: .failure(NSError(domain: "Error", code: 0))) //Errorを流して終了

次に、CurrentValueSubject。

let cvSubject = CurrentValueSubject<Int,Never>(100)

print(cvSubject.value)
cvSubject.filter{$0.isMultiple(of: 3)}
.map { $0 + 20 }
.sink { print($0) }

cvSubject.sink { print($0) }
cvSubject.send(3) //sendでもストリームは流れるのですが
print(cvSubject.value)//100 !!!! valueは変わりません
cvSubject.value = 33 //値を書き換えてもストリームが流れて
print(cvSubject.value)//33 !!!!

CurrentValueSubject の value プロパティは、send メソッドでは値が変わらないようで、valueを直接書き換えるのが正しい利用方法のようです。

(どちらもイベントは発火します)

多分 その2に続く...