[Swift]SwiftUIチュートリアル Section4に入門してみた。[Handling User Input編]

Swift

はじめに

前回からの続きでSwiftUIのチュートリアル入門で、[Handling User Input編]になります。

もと記事サイト

Handling user input | Apple Developer Documentation
In the Landmarks app, a user can flag their favorite places, and filter the list to show just their favorites. To create...

Step0

このセッションではObservable Objectを使ってlandmaark dataの変更をViewにバインドさせて反映するための準備をします。

Step1

プロジェクトナビゲーションからModelフォルダーにあるData.swiftを選択します。

Step2

ObservableObject protocolを準拠した新規Modelを作成するためにCombineをインポートします。

import Foundation
import Combine

final class ModelData: ObservableObject {
}

var landmarks: [Landmark] = load("landmarkData.json")

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) from main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

Step3

landmarksの配列を先程宣言したModelData内に移動します。

import Foundation
import Combine

final class ModelData: ObservableObject {
    var landmarks: [Landmark] = load("landmarkData.json")
}

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) from main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

Step4

landmarks配列の変更を反映するために@Publishedを付与します。

import Foundation
import Combine

final class ModelData: ObservableObject {
    @Published var landmarks: [Landmark] = load("landmarkData.json")
}

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) from main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

まとめ

今回はModelとView間のデータ変更をバインドするための準備でした。
@Stateで変数を一つずつ宣言するやり方もありますが、まとめてグループ化したい場合はObservableObjectを準拠させ、@ObservedObjectを使用して変数を宣言します。

コメント

タイトルとURLをコピーしました