ReactiveSwiftを克服する: Property (Part 5)

## この記事について

この記事は[Conquering ReactiveSwift: Property (Part 5)](https://medium.com/fueled-engineering/https-medium-com-hsusmita-conquering-reactiveswift-property-tutorial-5-c4e3dd38e94d)の翻訳です。

以下本文です。

# 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を用意しました。

```swift
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を定義してみましょう。

```swift
let property = Property(initial: 0, then: signalProducer)
```

ここで、初期値は0でそれに続く値がsignalProducerによって返される値です。

さきほど書いた通り、Propertyには`signal`と`producer`というプロパティがあり、両方とも監視することができます。しかし、両者の重要な違いは、signalは現在値を排出せず、それに続く値のみを排出することです。

```swift
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
*/
```

```swift
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は初期値だけで初期化することができます:

```swift
let mutableProperty = MutableProperty(1)
```

値の変更はこうします:

```swift
mutableProperty.value = 3
```

MutablePropertyの`signal`と`producer`はPropertyと同じように監視可能です。

MutablePropertyの便利な使い方はバインディングです。MutablePropertyを使うと以下のように書けます:

```swift
mutableProperty <~ signalProducer
```

このコードだと、`mutableProperty`の`value`が`signalProducer`によって決まります。

## まとめ

この記事でPropertyとMutablePropertyについてわかってもらえたら嬉しいです。サンプルコードは[こちら](https://github.com/hsusmita/conquering-reactive-swift/blob/master/ConqueringReactiveSwift/Paygrounds/Conquering-Reactive-Swift.playground/Pages/Action.xcplaygroundpage/Contents.swift)にあります。次回の記事では、Signalの高度な制御を可能にしてくれるActionについて紹介します。

## シリーズ内リンク集

1. [ReactiveSwiftを克服する: 導入 (Part 1)](https://qiita.com/taka1068/items/5d916f1e68cbcdce0121)
2. [ReactiveSwiftを克服する: 基本要素 (Part 2)](https://qiita.com/taka1068/items/9e6ccce4297832817444)
3. [ReactiveSwiftを克服する: SignalとObserver (Part 3)](https://qiita.com/taka1068/items/bdd0329202cea0e0c4b6)
4. [ReactiveSwiftを克服する: SignalProducer (Part 4)](https://qiita.com/taka1068/items/85211855bcee06e18566)
5. この記事です
6. [ReactiveSwiftを克服する: Action (Part 6)](https://qiita.com/taka1068/items/9ea40476076623c2a910)