はじめに
Subjectsに関して調べたことや作ったサンプルを記載します。
開発環境
- macOS Big Sur 11.5.2
- Xcode 12.5.1
- Swift 5.4.2
本題
Subjectsとは
Publishersの一種。他のPublishersと何が違うかというと、Subjectsは自身の持つ"send(_:)"メソッドを使うことで、外部からSubjects以下に定義したOperatorsやSubscribersへ値を注入したり、イベントを発火させることができる。また、"send(completion:)"メソッドで値の公開(Publish)が正常に完了したのか、エラーが発生して終了したかどうかをSubscribersへ伝えることができる。(現状の認識に合わせて意訳してしまっているため、正確な内容は以下の参考URLを読んでください)
※参考:
- https://developer.apple.com/documentation/combine/subject
- https://developer.apple.com/documentation/combine/using-combine-for-your-app-s-asynchronous-code
"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などで実践的なコードを探して読んでみようと思います。
参考
-
https://developer.apple.com/documentation/combine/passthroughsubject
-
https://developer.apple.com/documentation/combine/subject/send(_:)
-
https://developer.apple.com/documentation/combine/subject/send(completion:)
-
https://developer.apple.com/documentation/combine/using-combine-for-your-app-s-asynchronous-code
-
https://developer.apple.com/documentation/combine/subscribers/completion
-
https://developer.apple.com/documentation/combine/just/sink(receivecompletion:receivevalue:)