リアクティブプログラミング、Combine の個人的なメモ

時間があるとリアクティブプログラミングの調査は行っているのですが、毎回まとめる前に忘れてしまうということを繰り返していたので、今回はまとめてみた。
業務でいつも最新の手法のみを使っているわけではないので、習得してもまとめておかないと忘れちゃうんですよね。(笑)

リアクティブプログラミングの定義

非同期イベントの処理を宣言的な記述で書くプログラミング。

もう少しイメージしやすい表現だと、データ流れをイベントのストリームとして表現し、ストリームに応じた振る舞いをさせる考え方。

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を取り入れる

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です