Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【Combine】Subjectsの概要

 

はじめに

Subjectsに関して調べたことや作ったサンプルを記載します。

 

開発環境

 

本題 

Subjectsとは

Publishersの一種。他のPublishersと何が違うかというと、Subjectsは自身の持つ"send(_:)"メソッドを使うことで、外部からSubjects以下に定義したOperatorsやSubscribersへ値を注入したり、イベントを発火させることができる。また、"send(completion:)"メソッドで値の公開(Publish)が正常に完了したのか、エラーが発生して終了したかどうかをSubscribersへ伝えることができる。(現状の認識に合わせて意訳してしまっているため、正確な内容は以下の参考URLを読んでください)

※参考:

 

"send(_:)"メソッドの挙動を確認する

以下のサンプルは、ボタンを選択するたびにPassthroughSubjectのsend(_:)メソッドを使って、ランダムな数字をSubscriberに公開している。

ContentView.swift
import SwiftUI

struct ContentView: View {
    @ObservedObject private var viewModel: ContentViewModel
    
    init(viewModel: ContentViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        Button("Sample") {
            viewModel.onTapped()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(viewModel: ContentViewModel())
    }
}

 

ContentViewModel.swift
import Combine

final class ContentViewModel: ObservableObject {
    private var cancellables = Set<AnyCancellable>()
    
    private lazy var subject = PassthroughSubject<Int, Error>()
    
    enum SampleError: Error {
        case error
    }
    
    init() {
        subject
            .sink(receiveCompletion: {
                print ("completion:\($0)")
            },
            receiveValue: {
                print("\($0)")
            })
            .store(in: &cancellables)
    }
    
    func onTapped() {
        // sendの挙動チェック
        let randomNumber = Int.random(in: 1...10)
        subject.send(randomNumber)
        
        // 値の公開が正常に完了したことをSubscriberに通知する挙動を確認したい場合は、以下のコメントアウトを外す
        //        subject.send(completion: .finished)
        
        // エラーで終了する挙動を確認したい場合は、以下のコメントアウトを外す
        //        subject.send(completion: .failure(SampleError.error))
    }
}

 

おわりに

Subjectsは便利で多用してしまいそうなので、正しい使い所を理解するために、GitHubなどで実践的なコードを探して読んでみようと思います。

 

参考