[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 this feature, you’ll start by adding a ...

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をコピーしました