この記事について
この記事はConquering ReactiveSwift: Property (Part 5)の翻訳です。
以下本文です。
ReactiveSwiftを克服する: Property (Part 5)
ReactiveSwiftを克服するシリーズのパート5へようこそ。前回の記事では、SignalProducerを生成、start、監視する方法を学びました。この記事では、PropertyとMutablePropertyという考え方について議論していきましょう。
定義
Propertyは監視可能なコンテナで、値が変わるたびに値を排出します。PropertyProtocolに準拠していて、PropertyProtocolは次のようなプロパティを持ちます:
- value: 現在の値を表します。
- producer: 現在の値と、それに続く値を送るSignalProducerです。Propertyが破棄されたり、これ以上変更がない場合は、SignalProducerも完了し、それ以降値を送りません。
- signal: 以降に続く値を送るSignalです。**現在の値は送りません。**Propertyが破棄されたり、これ以上変更がない場合は、SignalProducerも完了し、それ以降値を送りません。
なぜ便利なのか?
値だけを扱い、エラーのことは考えない場合に便利です。
前回の記事の例を考えてみましょう。
50秒の間、5秒に一度の間隔で経過時間を出力しなさい。
これに対して私たちは次のようなSignalProducerを用意しました。
let signalProducer: SignalProducer<Int, NoError> = SignalProducer { (observer, lifetime) in
let now = DispatchTime.now()
for index in 0..<10 {
let timeElapsed = index * 5
DispatchQueue.main.asyncAfter(deadline: now + Double(timeElapsed)) {
guard !lifetime.hasEnded else {
observer.sendInterrupted()
return
}
observer.send(value: timeElapsed)
if index == 9 {
observer.sendCompleted()
}
}
}
}
ここのエラー型にあたるNoError
の意味は、エラーの処理が必要がないことを表していることに注意してください。このような例は、Propertyの良い使いどころです。
それでは、Propertyを定義してみましょう。
let property = Property(initial: 0, then: signalProducer)
ここで、初期値は0でそれに続く値がsignalProducerによって返される値です。
さきほど書いた通り、Propertyにはsignal
とproducer
というプロパティがあり、両方とも監視することができます。しかし、両者の重要な違いは、signalは現在値を排出せず、それに続く値のみを排出することです。
property.producer.startWithValues { value in
print("[Observing SignalProducer] Time elapsed = \(value)")
}
/* 出力:
[Observing SignalProducer] Time elapsed = 0
[Observing SignalProducer] Time elapsed = 0
[Observing SignalProducer] Time elapsed = 5
[Observing SignalProducer] Time elapsed = 10
[Observing SignalProducer] Time elapsed = 15
[Observing SignalProducer] Time elapsed = 20
[Observing SignalProducer] Time elapsed = 25
[Observing SignalProducer] Time elapsed = 30
[Observing SignalProducer] Time elapsed = 45
[Observing SignalProducer] Time elapsed = 35
[Observing SignalProducer] Time elapsed = 40
*/
property.signal.observeValues { value in
print("[Observing Signal] Time elapsed = \(value)")
}
/* 出力
[Observing Signal] Time elapsed = 0
[Observing Signal] Time elapsed = 5
[Observing Signal] Time elapsed = 10
[Observing Signal] Time elapsed = 15
[Observing Signal] Time elapsed = 20
[Observing Signal] Time elapsed = 25
[Observing Signal] Time elapsed = 30
[Observing Signal] Time elapsed = 35
[Observing Signal] Time elapsed = 40
[Observing Signal] Time elapsed = 45
*/
この例では、SignalProducerからの値を受け取るPropertyを生成しました。Signalからの値を受け取るPropertyも生成することも可能です。
MutableProperty
MutablePropertyは、Propertyと同じく、監視可能なコンテナです。しかし、値を直接変更することができる点が異なります。PropertyProtcolに準拠しているのはPropertyと同じです。
MutablePropertyは初期値だけで初期化することができます:
let mutableProperty = MutableProperty(1)
値の変更はこうします:
mutableProperty.value = 3
MutablePropertyのsignal
とproducer
はPropertyと同じように監視可能です。
MutablePropertyの便利な使い方はバインディングです。MutablePropertyを使うと以下のように書けます:
mutableProperty <~ signalProducer
このコードだと、mutableProperty
のvalue
がsignalProducer
によって決まります。
まとめ
この記事でPropertyとMutablePropertyについてわかってもらえたら嬉しいです。サンプルコードはこちらにあります。次回の記事では、Signalの高度な制御を可能にしてくれるActionについて紹介します。