本記事は下記を参考にしています。
前々からやりたかったSwiftUIとCombineを組み合わせた実装をやってみる!
開発環境
> xcodebuild -version Xcode 13.1 Build version 13A1030d
作ったもの
2.5秒ごとに [1, 2, 3, 4, 5]
をシャッフルして文字列として表示する。
コード
import SwiftUI import Combine struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { Text(viewModel.toString()) .padding() } } final class ViewModel: ObservableObject { @Published var numbers: [Int] = [1, 2, 3, 4, 5] private var cancellables = Set<AnyCancellable>() init() { Timer.publish(every: 2.5, on: .main, in: .default) .autoconnect() .sink(receiveValue: { [weak self] _ in guard let self = self else { return } self.numbers = self.numbers.shuffled() }) .store(in: &cancellables) } func toString() -> String { return numbers.reduce("") { partialResult, number in return partialResult + number.description } } }
@StateObject
@StateObjectがよく分からかったので調べた。
@StateObject
A property wrapper type that instantiates an observable object.
https://developer.apple.com/documentation/swiftui/stateobject
ObservableObjectをインスタンス化する(際に付与する)Property Wrapper。
ObservableObject
A type of object with a publisher that emits before the object has changed.
https://developer.apple.com/documentation/Combine/ObservableObject
よく分からないので書く。
import Combine final class ViewModel: ObservableObject { @Published var numbers: [Int] = [1, 2, 3, 4, 5] func shuffle() { numbers = numbers.shuffled() } func toString() -> String { return numbers.reduce("") { partialResult, number in return partialResult + number.description } } } let viewModel = ViewModel() let cancellable = viewModel.objectWillChange .sink { _ in print("will change: \(viewModel.toString())") } viewModel.shuffle() // "will change: 12345" print("did change: \(viewModel.toString())") // did change: 54213
ObservableObjectに準拠しているクラスのインスタンスの@Publishedが付与されているプロパティが変更される際に、変更前の値を取得できる。