0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Swift Combine: PassthroughSubject の使い方と実践例

Posted at

はじめに

Swift の Combine フレームワークは、リアクティブプログラミングを実現するためのツールです。その中の PassthroughSubject は、イベントを外部から送信し、それを購読者が受け取る仕組みを提供します。


PassthroughSubject とは?

PassthroughSubject は、イベントが発生した際にそのデータを即座に購読者へ通知するための Combine の仕組みの一つです。状態を保持しないため、新しい購読者は過去のデータを受け取ることはできません。

CurrentValueSubject との違い

PassthroughSubject CurrentValueSubject
データの保持 なし 最新の値を保持
過去のデータの取得 不可 可能
初期値 必要なし 必要

基本的な使い方

1. PassthroughSubject の定義

まずは PassthroughSubject を定義します。

import Combine

class EventManager {
    var subject = PassthroughSubject<String, Never>()
}

ここで PassthroughSubject<String, Never> は、String 型のデータを送信し、エラーは発生しない (Never) ことを示しています。


2. 購読者の追加

購読者(sink)を使って、データを受け取る処理を実装します。

let manager = EventManager()
let cancellable = manager.subject.sink { value in
    print("受信: \(value)")
}

3. データを送信する

購読者を追加した後に、send メソッドを使ってデータを送信します。

manager.subject.send("イベント発生!")
// コンソール出力: 受信: イベント発生!

購読者が存在する場合、このデータは即座に送信され、sink 内の処理が実行されます。


4. 購読のキャンセル

購読を続けると、メモリリークの原因になる場合があります。そのため、AnyCancellable を使って購読を管理し、適切なタイミングでキャンセルするのが望ましいです。

class EventManager {
    var subject = PassthroughSubject<String, Never>()
    private var cancellables = Set<AnyCancellable>()

    init() {
        subject
            .sink { value in
                print("受信: \(value)")
            }
            .store(in: &cancellables)
    }
}

これにより、EventManager のインスタンスが解放された際に購読も自動的にキャンセルされます。


簡単なユースケース

1. ボタンのクリックイベントを通知

SwiftUI では、ボタンのクリックを PassthroughSubject を使って通知できます。

import SwiftUI
import Combine

class ButtonViewModel: ObservableObject {
    var buttonTapped = PassthroughSubject<Void, Never>()
}

struct ContentView: View {
    @StateObject private var viewModel = ButtonViewModel()
    
    var body: some View {
        Button("タップ") {
            viewModel.buttonTapped.send()
        }
        .onAppear {
            viewModel.buttonTapped.sink {
                print("ボタンがタップされました!")
            }
        }
    }
}

2. API リクエストのステータスを通知

PassthroughSubject を利用して、API リクエストの状態を購読できます。

class APIService {
    var responseSubject = PassthroughSubject<String, Never>()
    
    func fetchData() {
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            self.responseSubject.send("データ取得完了")
        }
    }
}

let apiService = APIService()
let cancellable = apiService.responseSubject.sink { response in
    print(response)
}

apiService.fetchData()
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?