SwiftChainingの解説記事その5です。
SwiftChainingとは何か?というのは、こちらの最初の記事を参考にしてください。
前回の記事では、監視対象のオブジェクトのchain()
を呼んだ後に繋げて書く「処理を構築する関数」の解説をしました。
今回は、「バインディング処理を構築した後に確定させて監視を開始する関数」について少し詳しく解説しようと思います。
今まで何度も出てきたものになるのですが、end
とsync
についてです。
バインディング処理を確定する関数
end
end
は、chain()
の後に繋げて書いて構築したバインディング処理を確定し、監視を開始します。
let notifier = Notifier<Int>()
let chain1 = notifier.chain()
// ここではまだ監視は始まらず処理が追加できる
let chain2 = chain1.do { _ in }
// endを呼んで処理が確定し監視が始まる
let observer = chain2.end()
// endの後に処理を追加しようとするとfatalErrorになる
// chain2.do { _ in }
observer.invalidate()
// invalidateされたので監視は止まる
end
は返り値にObserver
のインスタンスを返し、それ以降はもう処理をつなげることはできません。処理を追加しようとしてもfatalError
になります。
なお、end
を呼んだ時点では何もイベントは起きず、その後監視対象のオブジェクトからイベントが発生したらchain()
以降で書いた処理が実行されます。バインディングという意味では、監視を開始したタイミングで値を知りたくなるのですが、その場合は次で紹介するsync
を呼ぶことになります。
sync
sync
は、chain()
の後に繋げて書いて構築したバインディング処理を確定し、1度イベントを送信させた上で監視を開始します。
let sender = ValueHolder(1)
let receiver = ValueHolder(0)
let observer = sender.chain()
.sendTo(receiver)
.sync()
// syncが呼ばれたことによってreceiverは1になっている
print(receiver.value)
sender.value = 2
// 変更を監視しreceiverは2になっている
print(receiver.value)
監視対象のオブジェクトが常に値を返すことのできる場合に使うことができ、sync
を呼ぶと内部的にend
を呼びつつ、監視対象のオブジェクトから一度イベントを送らせる事が出来ます。
end
だと変更があったら送られるだけですが、sync
で監視し始めにも送ることによって繋げた値を同期させられるという感じです。
なお、監視対象のオブジェクトからはいくつもchain()
を呼んで複数の場所から監視ができ、普通に対象の値が変更された時のイベントはその全部に対して送られますが、sync
を呼んだ時のイベントはそのひとつだけに送られます。
ちなみに、ここで出てきた「常に値を返すことのできる」オブジェクトというのは何かと言うと、今までの記事で紹介したものの中では…
- ValueHolder
- KVOAdapter
というクラスのオブジェクトになります。
逆に「値を返す事ができない」クラスは…
- Notifier
- NotificationAdapter
- UIControlAdapter
などです。後者のような値を持っていなくて返すことができないオブジェクトからのみ処理が繋がっている場合はend
でしか終わらせることができません。
merge
などで値を返せるオブジェクトと返せないオブジェクトの処理を混ぜた場合にはsync
を呼ぶことはできますが、無い袖は振れないので値を返せるオブジェクトからのみイベントが送信されます。
なお、「値を返せる」「値を返せない」の違いは何かと言うと、SwiftChaining
的には適合しているプロトコルにFetchable
が含まれているかということなのですが、これは次の記事で解説します。