오늘은 Swift Concurrency를 공부하기 위해 진행하던 사이드 프로젝트에 async/await를 적용하려고 했어요. 이런 방식으로 하면 된다고 해서 한번 해 봤는데...
먼저 URLSession.shared.data(for:)
메서드는 튜플 (Data, URLResponse)
를 반환해요:
let (data, response) = try await URLSession.shared.data(for: request)
// ↑ ↑
// 실제 응답정보
// 데이터 (상태코드 등)
전송 성공/실패만 확인하면 되는 경우, 데이터는 사용하지 않으므로:
let (_, response) = try await URLSession.shared.data(for: request)
// ↑
// 언더스코어 = "이 값은 사용하지 않겠다"
func sendGossip(_ content: String) async throws {
let url = URL(string: "http://localhost:3000/api/gossip")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = [
"content": content,
"deviceId": deviceId
]
do {
request.httpBody = try JSONSerialization.data(withJSONObject: body)
} catch {
print("❌ JSON 직렬화 오류: \(error)")
return
}
let (_, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
self.dailyUsage += 1
print("✅ 뒷담화 전송 완료")
}
Button("전송") {
Task {
try await gossipManager.sendGossip(newMessage)
}
isComposing = false
newMessage = ""
}
Button("전송") {
Task {
do {
try await gossipManager.sendGossip(newMessage)
print("✅ 성공!")
isComposing = false
newMessage = ""
} catch {
print("❌ 에러: \(error)")
}
}
}
또는 더 간단하게:
Button("전송") {
Task {
try await gossipManager.sendGossip(newMessage)
isComposing = false
newMessage = ""
}
}
실행 순서의 차이
Task { }
시작 (백그라운드에서 비동기 실행)isComposing = false
즉시 실행 ⚡️newMessage = ""
즉시 실행 ⚡️sendGossip
완료Task { }
시작sendGossip
완료까지 대기isComposing = false
실행newMessage = ""
실행위치 | 실행 시점 | 특징 |
---|---|---|
Task 외부 | 즉시 실행 | Task 완료를 기다리지 않음 |
Task 내부 | await 완료 후 | 순차 실행 보장 |
결론: UI 상태 변경 코드는 Task 내부에 넣어서 비동기 작업 완료 후에 실행되도록 해야 함!