[Swift]SwiftUIチュートリアル Section1に入門してみた。[Building Lists and Navigation編]

Swift

はじめに

前回からの続きでSwiftUIのチュートリアル入門になります。

もと記事サイト

Building lists and navigation | Apple Developer Documentation
With the basic landmark detail view set up, you need to provide a way for users to see the full list of landmarks, and t...

Step0

前回までに作成したプロジェクトと、今回のチュートリアルでダウンロードできるjsonファイルを使って、jsonファイルのデータをリスト表示していきます。

Step1

チュートリアルに添付されているプロジェクトをダウンロードし、その中にあるlandmarkData.jsonを現在作業しているXcodeプロジェクトのナビゲーションにドラッグ&ドロップします。
すると、ダイアログが表示されるので画像のようにチェックをします。(Add to targetsはご自身のプロジェクトの名前になっています。)

こんな感じでlandmarkData.jsonが追加されています。

Step2

上の方にあるナビゲーションバーからFile > New > Fileを選択。

ファイル一覧が表示されるので、User Interface欄にある、SwiftUI Viewを選択して、Nextボタンを押します。ファイル名をLandmark.swiftとし、新規で作成します。

Step3

Landmarkという名前のStructを作成します。
landmarkData.jsonから取り出したランドマークごとのデータを保存するために使用します。
Codableを付けることで、json内の項目とStruct内の項目をマッピングしてデータを自動で取得できるようにしています。

import Foundation

struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
}

Step4

プロジェクトナビゲーションにあるAssets.xcassetsをクリックし、
チュートリアルのプロジェクト内にあるJPGファイルをドラッグ&ドロップします。

Step5

jsonファイルからファイル名を読み込むためのimageNameプロパティと、Viewに画像を表示するためにasset catalogから画像を取得するimageプロパティを追加します。

import Foundation
import SwiftUI

struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
    
    private var imageName: String
    var image: Image {
        Image(imageName)
    }
}

Step6

jsonファイルから経度、緯度を取得するためのcoordinatesプロパティを追加します。
landmarkData.jsonを確認すると、coordinatesの中にlongitudelatitudeが入れ子になっています。
StructとしてCoordinatesを新規作成し、Landmarkprivate var coordinates: Coordinatesを持たせています。

import Foundation
import SwiftUI

struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
    
    private var imageName: String
    var image: Image {
        Image(imageName)
    }
    
    private var coordinates: Coordinates

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

Step7

経度、緯度からMapKit frameworkのCLLocationCoordinate2Dを生成します。

import Foundation
import SwiftUI
import CoreLocation

struct Landmark: Hashable, Codable {
    var id: Int
    var name: String
    var park: String
    var state: String
    var description: String
    
    private var imageName: String
    var image: Image {
        Image(imageName)
    }
    
    private var coordinates: Coordinates
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }

    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}

Step8

Step2と同じ手順でModelData.swiftファイルを作成します。

Step9

load(_:)メソッドを作成し、パラメータで渡したjsonファイル名を使ってjsonを取得し、jsonをオブジェクトに変換します。

import Foundation

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)")
    }
}

Step10

load(_:)の呼び出しもとを作成します。
パラメータでlandmarkData.jsonを渡し、ファイル名からjsonファイルを取得。
取得したjsonファイルからjsonを取得し、オブジェクトに変換したものを配列で返却しています。

import Foundation

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)")
    }
}

Step11

ファイルの役割ごとにグループ化し、管理しやすくします。
グループ化したいファイルをCommandを押しながらクリックで選択、上部のナビゲーションバーからFile > New > Group from Selectionを選択します。

以下のようにファイルをグループ化して、フォルダに名前を付けました。

まとめ

リスト表示するための下準備で、あまりSwiftUI関係ない内容ではありましたが、
jsonからオブジェクトに変換するModelData.swiftに関しては勉強になったかなという感じでした。
次回からは実際にView側を作成していきます。

コメント

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