여러 랜드마크의 리스트와 상세정보를 볼 수 있도록 해주고, 다양한 디바이스의 크기에 맞게 화면을 구성할 수 있도록 해줍니다.


1. Landmark 모델 만들기

Untitled

**// Landmark.swift
import Foundation
import SwiftUI
import CoreLocation

// landmarkData.json 파일의 키:값에 맞는 구조체를 정의해준다.
// Codable 프로토콜 : 구조체와 데이터 파일 간에 데이터를 더 쉽게 이동할 수 있게 해준다. Codable의 컴포넌트인 Decodable을 사용해서 파일로부터 데이터를 읽어올 수 있다.
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
    // MapKit 프레임워크와 상호작용 하기 좋도록 좌표 프로퍼티를 처리해준다.
    var locationCoordinate: CLLocationCoordinate2D {
        CLLocationCoordinate2D(
            latitude: coordinates.latitude,
            longitude: coordinates.longitude)
    }
    
    struct Coordinates: Hashable, Codable {
        var latitude: Double
        var longitude: Double
    }
}**
**// ModelData.swift
import Foundation

// landmarkData.json 파일을 불러와서 배열로 저장합니다.
var landmarks: [Landmark] = load("landmarkData.json")

// json 파일로부터 데이터를 불러오는 제네릭 함수
// load()는 Decodable 프로토콜을 준수하는 파라미터만 받을 수 있음
func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    // 앱의 메인 번들로부터 JSON 파일을 갖고옵니다.
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    // json 파일로부터 데이터를 추출합니다.
    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)")
    }
}**

2. Row View 만들기

**// LandmarkRow.swift**
import SwiftUI

struct LandmarkRow: View {
    **var landmark: Landmark**
    
    var body: some View {
        **HStack {
            landmark.image // landmark.image는 Image() 뷰임
                .resizable()
                .frame(width: 50, height: 50)
            Text(landmark.name)
            
            Spacer() // 랜드마크 정보를 행의 왼쪽으로 밀어주기 위해 넣어줌
        }**
    }
}

struct LandmarkRow_Previews: PreviewProvider {
    static var previews: some View {
        **LandmarkRow(landmark: landmarks[0]) // 이니셜라이저에 landmark 파라미터를 넣어준다.**
    }
}

Untitled