SwiftUI x Combine 練習1

本記事は下記を参考にしています。

blog.studysapuri.jp


前々からやりたかった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が付与されているプロパティが変更される際に、変更前の値を取得できる。

参考