この記事は、ニフティグループ Advent Calendar 2021 13日目の記事です。
ニフティライフスタイル所属エンジニアから3人目の投稿です!
iOSアプリエンジニアなのでiOSアプリについての記事を投稿します。
はじめに
WWDC 2019にてCombineが発表されて早2年、ようやくiOS12のサポートが切れて自分のプロダクトにCombineが導入できる!って方もいるのではないでしょうか...
私が携わっているニフティ不動産アプリもついにiOS13以上サポートになり、今年初めてCombineをプロダクトコードに導入しました。
DelegateやClosureを駆使して実装してきた私にとって、Combineの宣言的な概念や実装を理解するのは結構大変でした。
今回は自分の復習も兼ねて、Combineをざっと学んでみたけどこんな時にどんな文法を使えば良いんだっけ?というときに使えるCombineチートシートを作成しました!
とりあえず何かをCombineを使って流してみたい
公式で用意されたPublisherを使えます。
Just
値を即時に1回だけ流すことができます。エラーは流せません。
ダミーの値を流して動作を確認したい時などに使えます。
Just("Taro")
.map { name in
"Hello, \(name)!"
}
.sink { message in
print(message)
}.store(in: &cancellables)
Hello, Taro!
Future
値かエラーを非同期的に1回だけ流すことができます。
クロージャで書かれているAPIをCombineで流したい時など、返却値をPublisherに変換するときに、ラップして使うことができます。
注意としてはインスタンスを生成した時点でFuture
の中を実行してしまうので、Deferred
で囲うことでSubscribeした時に初めて実行されるようになります。
func testPublisher() -> AnyPublisher<Int, Never> {
Deferred {
Future<Int, Never> { (promise) in
// 非同期処理
DispatchQueue.global(qos: .userInitiated).async {
print(Thread.isMainThread)
promise(.success(1))
}
}
}.eraseToAnyPublisher()
}
testPublisher().sink { int in
print(int)
}.store(in: &cancellables)
false
1
Empty
「Never」パブリッシャーを作成し、終了だけを流します。
Publisherを生成しなければいけないが、値もエラーも流したくないときに利用します。
私はテストコードなどでとりあえず何かを流さないといけなかったり、メソッド内が未実装のときにビルドエラーにならないように仮で実装するときに利用します。
Empty().eraseToAnyPublisher()
定期的に値を流し続けたい
Subjects
Subscriber(値を受け取る側)へ値を流すことができます。出力終了の通知を送るまで、send
を呼ぶことで継続的に値を流し続けることができます。
Subjectsには2種類あります。
CurrentValueSubject
最後に出力した値を一つ保持し、値を流すたびに保持する値も更新されます。
Subscriber(値を受け取る側)が購読を開始したときに初期値が欲しいときはこちらを利用します。
let subject = CurrentValueSubject<Int, Never>(0)
subject.sink { int in
print(int)
}.store(in: &cancellables)
subject.send(1)
subject.send(2)
subject.send(3)
0
1
2
3
PassthroughSubject
PassthroughSubjectは値を保持せず値を流します。
let subject = PassthroughSubject<Int, Never>()
subject.sink { int in
print(int)
}.store(in: &cancellables)
subject.send(1)
subject.send(2)
subject.send(3)
1
2
3
プロパティをPublisherにしたい
@Published
Property Wrappers
という機能を使って@Published
を先頭につけることによって、プロパティをPublisherにすることができます。
class Human {
@Published var name: String = "Taro"
}
let human = Human()
human.$name
.sink { name in
print("Hello, \(name)!")
}.store(in: &cancellables)
human.name = "Jiro"
human.name = "Saburo"
Hello, Taro!
Hello, Jiro!
Hello, Saburo!
複数のPublisherをまとめて受け取りたい
さまざまな書き方がありますが、以下の記事がとてもわかりやすくて参考になったのでリンクを紹介します。
【Swift】CombineフレームワークのCombining Operators(Publisherを結合するOperator)の動きを確認する
私は merge
やcombineLatest
をよく使います。
まとめ
まだまだ他にもCombineの文法はたくさんありますが、私のプロダクトでよく使ったものをまとめました。
これからCombineを学ぶ人にとって参考になったら嬉しいです!