49: CupcakeCorner, part 1

그루두·2024년 6월 22일
0

100 days of SwiftUI

목록 보기
56/108

100 days of swiftui: 49

load data from url

swiftui에서 데이터를 불러오려면 먼저 불러올 데이터의 형태를 틀로 만들어야 한다. 예로 노래를 불러오기 위해서 노래의 정보를 Result, 그리고 그의 배열 형태인 Response를 만들어줬다.

struct Response: Codable {
    var results: [Result]
}

struct Result: Codable {
    var trackId: Int
    var trackName: String
    var collectionName: String
}

struct ContentView: View {
    @State private var results = [Result]()
    var body: some View {
        List {
            ForEach(results, id: \.trackId) { result in
            // ...

깃헙 링크

url에서 데이터를 불러오는 단계는 3가지로 나뉜다.
1. url이 유효한지 읽기(read)
2. data를 가져오기(fetch)
3. data를 원하는 형태로 풀이하기(decode)

fetch할 때는 프로젝트 외부에서 데이터를 읽어서 가져오기 때문에 시간이 걸리고, 인터넷에 연결되어 있지 않거나, 데이터가 없거나 등등 다양한 에러가 일어날 수 있다. 이를 await로 기다리고 동기화하는 처리 과정이 필요하다. 이 과정을 진행하는 함수를 async로 정의해야 한다.

    func loadData() async {
        // 1: read url
        guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=song") else {
            print("Error: Invalid url")
            return
        }
        do {
            // 2: fetch data
            let (data, _) = try await URLSession.shared.data(from: url)
            // 3: decode data
            if let decoded = try? JSONDecoder().decode(Response.self, from: data) {
                results = decoded.results
            }
        } catch {
            print("Error: Invalid data")
        }
    }

깃헙 링크

💡 resultsResponse가 아닌 Result를 사용하고 decode할 때 왜 Response를 활용하는지에 대해 처음에 이해를 못했는데, 이 틀(Response)로 해석하고 그의 속성인 results를 지역 변수 results에 입력하기 위함임을 깨달았다!

load image from url with AsyncImage

image의 경우 AsyncImage로 불러올 수 있다. 아래 사진은 url로 사진을 불러왔을 때 보이는 형태다. 이처럼 AsyncImage는 사진을 불러오되 사진처럼 다룰 줄 몰라서 resizable이나 frame modifier가 곧장 적용되지 않는다.

AsyncImage로 불러온 이미지의 다루는 방법은 다양한다. 먼저 scale을 이용하여 이미지의 크기를 간단하게 조절할 수도 있다.

struct ContentView: View {
    var body: some View {
        AsyncImage(url: URL(string: "https://hws.dev/img/logo.png"), scale: 5)
    }
}

혹은 아래 코드처럼 Image처럼 다룰 수도 있다. 이미지를 로드하기 전까지는 placeholder로 대신 나타낼 수 있다.

AsyncImage(url: URL(string: "https://hws.dev/img/logo.png")) { image in
    image
        .resizable()
        .scaledToFit()
} placeholder: {
    Color.red
}
.frame(width: 200, height: 200)

좀 더 세분화하여 이미지를 불러오기 전, 후, 이미지 불러오기 실패했을 때를 나누고 설정할 수도 있다.

struct ContentView: View {
    var body: some View {
        AsyncImage(url: URL(string: "https://hws.dev/img/logo.png")) { phase in
            if let image = phase.image {
                image
                    .resizable()
                    .scaledToFit()
            } else if phase.error != nil {
                Text("Error: Failed to load the image")
            } else {
                ProgressView()
            }
        }
        .frame(width: 100)
    }
}

깃헙 링크

disabled

Form에서 여러 값을 입력받는 경우가 있다. 그 값을 전달할 때 모든 값이 필요하거나, 특정 값이 어떠한 조건을 만족해야 하는 경우도 있는데, 이 조건이 성립되지 않을 때는 제출을 못하게 막을 수도 있다. 이를 disable로 설정할 수 있다.

예: name, email을 입력하지 않았을 때 버튼이 있는 Section을 disable 처리

struct ContentView: View {
    @State private var name = ""
    @State private var email = ""
    var body: some View {
        Form {
            Section {
                TextField("name", text: $name)
                TextField("email", text: $email)
            }
            Section {
                Button("Create an account") {
                    print("create!")
                }
            }
            .disabled(name.isEmpty || email.isEmpty)
        }
    }
}

혹은 Bool 값을 지니는 변수를 만들어 특정 조건을 성립하면 false로 변경하여 disable로 설정할 수도 있다.

예: name, email이 다섯 글자 이상 입력되어야 버튼을 활성화

    var IsDisabled: Bool {
        name.count < 5 || email.count < 5
    }
    // ...
    .disabled(IsDisabled)

깃헙 링크

profile
계속 해보자

0개의 댓글

관련 채용 정보