SwiftUIのビューは自動的に再描画され、通常は特定の関数をコールして再読み込みさせることはできません。どの変数を監視させるかをSwiftUIのビューに知らせるには、次の変数型を使用できます:
@State
@Binding
@Published
本記事ではこれらの変数型を紹介します。
@State
@State
変数を変更すると、そのビューは自動的に更新されます。
struct ContentView: View {
@State var textContent = "Loading..."
var body: some View {
Text(textContent)
.padding()
.onAppear(perform: {
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in
self.textContent = "Hello world!"
}
})
}
}
@Binding
ビュー・オブジェクトが多くのサブビューに分割されている場合、サブビューには @Binding
属性を定義し、主要ビューには @State
変数を定義することが可能です。
struct ContentView_SubView: View {
@Binding private var textContent: String
init(textContent: Binding<String>) {
_textContent = textContent
}
var body: some View {
Text(textContent)
.padding()
}
}
struct ContentView: View {
@State var textContent = "Loading..."
var body: some View {
ContentView_SubView(textContent: $textContent)
.onAppear(perform: {
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in
self.textContent = "Hello world!"
}
})
}
}
@ObservedObject
and @Published
例えば、もしSwiftUIのビューにユーザーのロケーションを表示したい場合、ヘルパークラスである LocationHelper
を書くことができます。
LocationHelper
は CLLocationManager
からロケーションを取得し、変数 userCoordinate
に座標を保存してくれます。
ObservableObject
プロトコルに準拠させるために LocationHelper
を、そしてプロパティ・ラッパーの @Published
を持たせるために userCoordinate
を設定できます。
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var userLocation: CLLocation?
let locationManager = CLLocationManager()
init(accuracy: CLLocationAccuracy) {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = accuracy
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
self.userLocation = location
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}
}
SwiftUIのビューでは LocationManager
に @ObservedObject
を追加することができます:
@ObservedObject var location: LocationManager
init() {
self.location = LocationManager(accuracy: kCLLocationAccuracyNearestTenMeters)
}
そして変数の変化を監視するために関数 .onChange
を使用できます。
struct ContentView: View {
@ObservedObject var location: LocationManager
init() {
self.location = LocationManager(accuracy: kCLLocationAccuracyNearestTenMeters)
}
var body: some View {
Form {
// TODO
}
.onChange(of: self.location.userLocation, perform: { value in
if let receivedUpdate = value {
self.locationsRecorded.append(locationEntry(timeStamp: receivedUpdate.timestamp, coordinate: receivedUpdate.coordinate))
}
})
}
}