μ‘μ‘ μλ νμΈμ μ΄μμμπ₯Έ. SwiftUIμ @Publishedλ₯Ό μ¬μ©νμ¬ λ€νΈμν¬ ν΅μ μ ν΅ν΄ λ°μμ¨ κ°μΌλ‘ λ³κ²½νλ λμ€ μλμ κ°μ κ²½κ³ λ©μμ§λ₯Ό νμΈνμ¬ μ΄λ₯Ό ν΄κ²°νλ λ°©λ²μ λν΄ ν¬μ€ν νκ³ μ ν΄μ.
Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
λ°±κ·ΈλΌμ΄λ μ€λ λμμ λ³κ²½ μ¬νμ λ°ννλ κ²μ νμ©λμ§ μμμ. λͺ¨λΈ μ λ°μ΄νΈμ λν κ°μ λ°νν λλ (
receive(on:)
κ³Ό κ°μ μ°μ°μλ₯Ό ν΅ν΄) λ©μΈ μ€λ λμμ μ€νμ 보μ₯νμΈμ.
μ Xcodeλ μμ κ°μ κ²½κ³ λ©μμ§λ₯Ό 보μ¬μ€ κ±ΈκΉμ? μλμμ κ²½κ³ λ©μμ§κ° λ°μν μ½λλ₯Ό ν λ² λ³΄λλ‘ ν΄μ.
import Foundation
class CoinViewModel: ObservableObject {
@Published var coin: String = ""
@Published var price: String = ""
init(coin: String) {
self.coin = coin
self.fetchPrice()
}
func fetchPrice() {
let urlString: String = "https://api.coingecko.com/api/v3/simple/price?ids=\(self.coin)&vs_currencies=krw"
guard let url: URL = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
guard let jsonObject: [String : Any] = try? JSONSerialization.jsonObject(with: data) as? [String : Any] else { return }
guard let values = jsonObject[self.coin] as? [String : Int] else { return }
guard let price = values["krw"] else { return }
// Publishing changes from background threads is not allowed;
// make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
self.price = "β©\(price)"
}.resume()
}
}
μμ μ½λλ₯Ό 보면 priceλ₯Ό URLSession
μ ν΅ν΄ κ°μ Έμ¨ dataλ‘ κ°μ λ³κ²½ν΄μ£Όκ³ μμ΄μ. μ΄ λ Xcodeμμλ μμ κ°μ΄ κ²½κ³ λ©μμ§λ₯Ό μλ €μ£Όκ³ μμ΄μ.
URLSession
μ Appleμ Foundation νλ μμν¬μμ μ 곡νλ ν΄λμ€λ‘, λ€νΈμν¬ μμ²μ μμ±νκ³ κ΄λ¦¬νλ λ° μ¬μ©ν΄μ. λΉλκΈ° λ€νΈμν¬ μμ
μ μννλ λ° λ리 μ¬μ©λλ©°, μΉ μλ²μ λ°μ΄ν°λ₯Ό μ£Όκ³ λ°κΈ° μν΄ μ£Όλ‘ HTTP μμ²μ μ¬μ©ν΄μ. μ΄λ₯Ό ν΅ν΄ μ±μ μΈν°λ·μ ν΅ν΄ λ°μ΄ν°λ₯Ό κ°μ Έμ€κ±°λ μλ²μ ν΅μ ν μ μμ΄μ.
URLSession
μ κ²½μ° λΉλκΈ° μ²λ¦¬λ₯Ό νμ¬ λ©μΈ μ€λ λλ₯Ό μ°¨λ¨νμ§ μμμ. λ°λΌμ μμ μ½λμ self.priceμ κ°μ λ³κ²½ν΄μ£Όλ λΆλΆμ μ±μ λ©μΈ μ€λ λμμ μ²λ¦¬νμ§ μκ³ λ³λμ μ€λ λμμ κ°μ λ³κ²½νκ³ μμ΄μ.
ν΄λΉ κ²½κ³ λ©μμ§λ SwiftUIμ λΉλκΈ° μ²λ¦¬μμ νν λ°μνλ λ¬Έμ λ‘, λ°±κ·ΈλΌμ΄λ μ€λ λμμ UIλ₯Ό μ λ°μ΄νΈνλ €κ³ νκ±°λ λΉλκΈ°λ‘ λ°νλ κ°μμ UIλ₯Ό λ³κ²½νλ €κ³ ν λ λ°μνλ μ€λ₯μμ. SwiftUIλ μ£Όλ‘ λ©μΈ μ€λ λμμ μ¬μ©νλλ‘ μ€κ³λμμΌλ©°, λ°±κ·ΈλΌμ΄λ μ€λ λμμ UIλ₯Ό μ λ°μ΄νΈνλ©΄ μμμΉ λͺ»ν λμ λλ μΆ©λμ΄ λ°μν μ μμ΄μ.
λ°λΌμ μ΄ μ΄μλ₯Ό ν΄κ²°νλ €λ©΄ SwiftUI λ·°μ μ
λ°μ΄νΈ, νΉν @Published
μμ± λλ Combine νΌλΈλ¦¬μ
μ κ΄λ ¨λ μ
λ°μ΄νΈλ₯Ό λ©μΈ μ€λ λμμ μννλλ‘ λ³΄μ₯ν΄μΌ ν΄μ.
DispatchQueue.main.async
λ GCD(Grand Central Dispatch)μ μΌλΆλ‘, iOS λ° macOS μ±μμ λΉλκΈ°μ μΌλ‘ μμ
μ λ©μΈ μ€λ λμμ μ€ννλλ‘ νλ μ€μν ν¨ν΄ μ€ νλμμ.
λ©μΈ μ€λ λλ λλΆλΆμ UI κ΄λ ¨ μμ
λ° μ¬μ©μ μΈν°νμ΄μ€ μ
λ°μ΄νΈλ₯Ό μ²λ¦¬νλ μ€λ λμμ. λ°λΌμ λ©μΈ μ€λ λμμ μ€νλμ΄μΌ νλ μμ
μλ UI μ
λ°μ΄νΈ, λ·° 컨νΈλ‘€λ¬μ λ©μλ νΈμΆ λ° μ¬μ©μ μ΄λ²€νΈ μ²λ¦¬κ° ν¬ν¨λΌμ. κ·Έλ¬λ λ°±κ·ΈλΌμ΄λ μ€λ λμμ λΉλκΈ° μμ
μ μννκ³ λμ€μ κ²°κ³Όλ₯Ό λ©μΈ μ€λ λλ‘ λ³΄λ΄μΌ ν λ DispatchQueue.main.async
λ₯Ό μ¬μ©ν΄μ.
DispatchQueue.global().async {
// λ°±κ·ΈλΌμ΄λ μ€λ λμμ λΉλκΈ° μμ
μ μν
// ...
DispatchQueue.main.async {
// λ©μΈ μ€λ λμμ μ€νλμ΄μΌ νλ μμ
// μ: UI μ
λ°μ΄νΈ
}
}
μ μ½λμμλ DispatchQueue.global().async
λ₯Ό μ¬μ©νμ¬ λ°±κ·ΈλΌμ΄λ μ€λ λμμ λΉλκΈ° μμ
μ μνν ν, DispatchQueue.main.async
λ΄λΆμμ λ©μΈ μ€λ λλ‘ μ ννμ¬ λ©μΈ μ€λ λμμ μ€νλμ΄μΌ νλ μμ
μ μνν΄μ.
DispatchQueue.main.async
λ₯Ό μ¬μ©νλ©΄ λ©μΈ μ€λ λμμ μ€νν΄μΌ νλ μ½λ λΈλ‘μ μ μνκ³ , λ©μΈ μ€λ λμμ λΉλκΈ°μ μΌλ‘ μ€νλλλ‘ μμ½ν μ μμ΄μ. μ΄λ κ² νλ©΄ UI μ
λ°μ΄νΈ λ° λ€λ₯Έ λ©μΈ μ€λ λμμ μνν΄μΌ νλ μμ
μ μμ νκ² μ²λ¦¬ν μ μμΌλ©°, μ±μ μλ΅μ±μ μ μ§ν μ μμ΄μ.
λ°λΌμ μ°λ¦¬λ URLSessionμ΄ λΉλκΈ° μ²λ¦¬λ₯Ό μλ£νκ³ UIλ₯Ό λ³κ²½ν μ μλλ‘ DispatchQueue.main.async
λ₯Ό ν΅ν΄ ν΄λΉ κ°μ λ³κ²½μ λ©μΈ μ€λ λμμ μ²λ¦¬ν μ μμ΄μ.
func fetchPrice() {
let urlString: String = "https://api.coingecko.com/api/v3/simple/price?ids=\(self.coin)&vs_currencies=krw"
guard let url: URL = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
guard let jsonObject: [String : Any] = try? JSONSerialization.jsonObject(with: data) as? [String : Any] else { return }
guard let values = jsonObject[self.coin] as? [String : Int] else { return }
guard let price = values["krw"] else { return }
// λ©μΈ μ€λ λμμ κ°μ λ³κ²½νλλ‘ νμ΄μ.
DispatchQueue.main.async {
self.price = "β©\(price)"
}
}.resume()
}
SwiftUIμ UI μ λ°μ΄νΈμ κ΄λ ¨ν μΈμ¬μ΄νΈκ° λΆμ‘±ν΄μ μκΈ΄ μ΄μμμ΄μ. μ΄λ² νΈλ¬λΈ μν μ ν΅ν΄ λ νλ² μ±μ₯νλ€κ³ μκ°ν΄μπ