CupcakeCorner 앱의 경우 한 주문에서 주문시키는 상품과 주소를 입력한다. 그래서 하나의 @Observable인 Order
인스턴스를 활용한다.
이때 OrderView, AddressView에서 하나의 인스턴스를 가지고(@State를 통해 새 인스턴스를 만들지 않으면서) 화면에 변화를 나타내기 위해 @Bindable을 사용하면 된다.
struct AddressView: View {
@Bindable var order: Order
var body: some View {
Form {
// ...
AddressView에서 내용을 입력하는 대로 바로 화면에 나타나고, OrderView로 이동하였다가 돌아와도 저장되어 있는 것을 확인할 수 있다.
주문의 세부 선택에 따라 cost
를 설정하고 이를 나타내는 CheckoutView를 설정했다.
💡 ScrollView가 휴대폰의 세로 길이보다 길지 않으면 Scroll이 되지 않게 하기 위해서 .scrollBounceBehavior(.basedOnSize)
를 설정했다.
사용자가 주문하기 버튼을 클릭하면 특정 url에 주문 정보를 encode해서 보내고, 이 주문에 대해 문제가 없으면 data를 받아 deconde할 수 있다.
func placeOrder() async {
guard let encoded = try? JSONEncoder().encode(order) else {
print("Error: Failed to encode order")
return
}
let url = URL(string: "https://reqres.in/api/cupcakes")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
do {
let (data, _) = try await URLSession.shared.upload(for: request, from: encoded)
let decodedOrder = try JSONDecoder().decode(Order.self, from: data)
confirmationMessage = "Your order for \(decodedOrder.quantity) x \(Order.types[decodedOrder.type].lowercased()) cupcakes is on its way!"
showingConfirmation = true
} catch {
print("Error: Get \(error.localizedDescription)")
return
}
}
static으로 설정한 types
는 Order.types
로 사용해야 한다. 그리고 placeOrder()
는 async 함수이기 때문에 즉각적으로 함수를 실행하고 기다리지 않는 버튼에서는 다음 설정이 필요하다.
Button("Place Order") {
Task {
await placeOrder()
}
}
이렇게 컵케이크 주문을 실행해보고 encode된 data를 살펴보면 아래와 같다.
💡 xcode에서 let url = URL(string: "https://reqres.in/api/cupcakes")!
이 코드 줄에 breakpoint를 찍고 시뮬레이터 실행이 멈추면, 터미널에 p String(decoding: encoded, as: UTF8.self)
를 입력하면 확인할 수 있다.
data의 이름이 내가 설정한 이름에 _
가 붙어있는 것을 확인할 수 있다. 마찬가지로 @Observable인 class의 매크로 때문인데, CodingKey로 미리 지정하면 이를 방지할 수 있다.
enum CodingKeys: String, CodingKey {
case _type = "type"
case _quantity = "quantity"
case _specialRequestEnabled = "specialRequestEnabled"
case _extraFrosting = "extraFrosting"
case _addSprinkles = "addSprinkles"
case _name = "name"
case _streetAddress = "streetAddress"
case _city = "city"
case _zip = "zip"
}
💡 다른 값에 따라 설정되거나 static인 속성 types
, hasValidAddress
, cost
를 Codingkeys에 설정하면 Order
가 Codable 프로토콜을 준수하지 못하는 에러가 발생한다.