LoginSignup
32
23

More than 1 year has passed since last update.

変数が変更されたときにSwiftUIのViewがリロードされるようにする(@State、@Binding、@Published・@ObservedObject)

Last updated at Posted at 2020-11-05

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 を書くことができます。

LocationHelperCLLocationManager からロケーションを取得し、変数 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))
            }
        })
        
    }
    
}

:relaxed: Twitter @MszPro

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。

32
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
23