時間があるとリアクティブプログラミングの調査は行っているのですが、毎回まとめる前に忘れてしまうということを繰り返していたので、今回はまとめてみた。
業務でいつも最新の手法のみを使っているわけではないので、習得してもまとめておかないと忘れちゃうんですよね。(笑)
リアクティブプログラミングの定義
非同期イベントの処理を宣言的な記述で書くプログラミング。
もう少しイメージしやすい表現だと、データ流れをイベントのストリームとして表現し、ストリームに応じた振る舞いをさせる考え方。
Combine概要
Combine が登場したのは 2019 年 6 月の WWDC。
iOS 13.0以上で使用できる。
オブジェクト間でイベントを伝える仕組みを提供する。
主要な要素と役割は、以下の通り。
- Publisher – 時間の経過に沿ってイベントを伝達する役割
- Operator – イベントを作成、もしくは処理する役割
- Subscriber – Publisher から送信されたイベントを処理する役割
- Cancellable – イベントをキャンセルできることを表現する役割
- Subscription – Publisher と Subscriber の購読を表現する役割
subjectに対して、複数のsubscribeを行うことができる。
複数のsubscriptionを扱う場合、storeメソッドでまとめて保持する。
Publisherは、sendメソッドでイベントをpublishする。
参考: Apple Developer Documentation | Combine
Publisher イベントを発行する
Publisher を subscribe することでイベントを受信できる。
PassthroughSubject クラス
CurrentValueSubject クラス
Justとは 値を1回だけ出力するPublisher。
Futureは、通信処理などで利用していたコールバック処理をCombineで実装する場合に使用する。
Subscriber イベントを購読する
イベントを受信する(購読する)subscribe処理
assignメソッド
sinkメソッド
var subscriptions = Set()
Operator 流れてくる値を加工する
map
filter
compactMap
combineLatest など
APIリクエストを行い、結果集合をメンバ変数に格納するサンプル
import Foundation
import Combine
final class SearchUserViewModel: ObservableObject {
@Published var text = ""
@Published var users = [User]()
private lazy var subject = PassthroughSubject<Void, Never>()
private var cancellables = Set<AnyCancellable>()
private let searchUserModel: SearchUserModelProtocol
init(searchUserModel: SearchUserModelProtocol) {
self.searchUserModel = searchUserModel
subject.sink(receiveValue: { _ in
searchUserModel.fetchUser(query: self.text)
.receive(on: RunLoop.main)
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
print(error)
}
}, receiveValue: {
self.users = $0
})
.store(in: &self.cancellables)
})
.store(in: &self.cancellables)
}
func searchButtonTapped() {
subject.send()
}
}
参考:【Combine】APIとの通信処理にCombineを取り入れる
Follow @redwing1300