| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- JPEG
- 캐러셀
- png
- NSTextStorage
- 타뷸레이션
- fetchdescriptor
- 무한스크롤
- heic
- github 시작하기
- TestFlight
- xcode 엔터 표시
- Tuist
- webp
- JPG
- 함께자라기
- contentalignmentpoint
- .pbxproj
- Cocoa Pod
- Firestore
- SwiftUI
- swift 모듈화
- 클린 아키텍처
- NSTextStorageDelegate
- 코드스쿼드
- xcode 공백 표시
- swiftdata
- 팀 개발을 위한 git
- 테스트 타겟
- nidthirdpartylogin
- spm 에러
- Today
- Total
Sure, Why not?
콜백 방식의 비동기 코드를 async/await으로 사용하기 본문

어제가 새해였던 것 같은데..
1월에 정신없이 달리고, 정신 차려 달력 보니 2월 1일이다.
시간이 정말 빠른 것 같다. 하하
1월의 다양한 경험 속에서
인상 깊었던 이슈 해결 과정을 기록하고자 한다.
네트워크통신을 비동기작업으로 하는 도중에, 데이터는 정상적으로 받아와지는 것을 확인했으나,
UI업데이트가 매끄럽지 않다는 것을 확인하였다.
해당 이슈의 원인을 여러 방면으로 탐색하는 와중에,
비동기 데이터 처리의 순서가 명확하지 않는 문제를 발견하게 되었다.
먼저 3가지의 키워드를 간단하게 짚고 넘어가고자 한다.
비동기는 어떠한 작업이 끝날 때까지 기다리지 않고, 다음 코드가 바로 실행되는 방식을 말한다.
콜백 함수는 특정 시점에 실행되는 함수를 말하며,
async는 비동기 함수임을 선언하고, await은 비동기 함수의 실행을 기다림으로써,
비동기 코드를 동기 코드처럼 읽기 쉽게 작성되도록 도와준다.
나는 콜백도 단순히 비동기, async/await도 비동기니깐
자동으로 기다려줄 거라고 생각했지만,
실제로는 기존의 콜백 방식을 명시적으로 비동기 작업의 완료를 처리해야 한다는 것을 간과하여 이슈를 경험하게 되었다.
해당 이슈의 원인 파악은 다음과 같다.
1. 비동기 흐름 문제
기존 코드에서는 네트워크 요청이 완료되기 전에 다음 코드가 실행되어, UI가 예상과 다르게 동작하는 문제가 발생했다.
즉, async 함수임에도 불구하고, completion handler의 완료를 제대로 기다리지 않는 것을 확인했다.
2. 콜백 방식의 한계
현재 Moya 프레임워크의 completion handler 방식을 사용하고 있다. 이로인해 비동기 호출이 중첩되고 흐름을 명확하게 제어하지 못하여, 데이터 일관성 문제가 있을 것으로 예상했다.
다음 상황은 좋아요 토글 기능에 관련된 것이다.
문제 코드와 결과
// ProductModel.swift
func postInterestToggle() async {
print("postInterestToggle 시작")
if isInterested {
NetworkService.shared.productService.deleteInterest(productId: id) { [weak self] result in
switch result {
case .success:
print("좋아요 성공")
self?.isInterested = false
default:
break
}
}
} else {
NetworkService.shared.productService.postInterest(productId: id) { [weak self] result in
switch result {
case .success:
print("좋아요 성공")
self?.isInterested = true
default:
break
}
}
}
print("postInterestToggle 완료")
}
// ProductItemView.swift
private var likeButton: some View {
Button {
// TODO: - 좋아요 API 연결
Task {
print("시작")
await product.postInterestToggle()
print("끝")
}
} label: {
product.isInterested ? Image(.icnHeartListSelect) : Image(.icnHeartList)
}
.padding(.trailing, 6)
}

보이는 결과처럼 비동기 처리를 명확하게 제어해야 하는 필요성을 느꼈으며,
withCheckedContinuation를 통해 async/await 패턴을 적용할 수 있는 것을 알아냈다.
https://developer.apple.com/documentation/swift/withcheckedcontinuation(isolation:function:_:)
withCheckedContinuation(isolation:function:_:) | Apple Developer Documentation
Invokes the passed in closure with a checked continuation for the current task.
developer.apple.com
공식문서를 보면 다음과 같은 내용을 확인할 수 있다.
비동기 함수와 콜백 기반 비동기 코드를 연결하는 기능을 제공한다.
콜백 기반 비동기 함수의 결과를 async함수에서 동기적으로 기다릴 수 있도록 변환해주는 것.
continuation.resume 을 호출해야 비동기 함수가 정상적으로 완료됨.
Swift의 Concurrency 시스템과 통합되어, 실행 흐름을 더 안전하게 관리할 수 있음
잘못된 사용을 방지하기 위해 resume()을 여러 번 호출하면 런타임 오류 발생한다.
해결코드와 결과
// ProductModel.swift
func postInterestToggle() async {
print("postInterestToggle 시작")
await withCheckedContinuation { continuation in
if isInterested {
NetworkService.shared.productService.deleteInterest(productId: id) { [weak self] result in
switch result {
case .success:
print("좋아요 성공")
self?.isInterested = false
default:
break
}
continuation.resume()
}
} else {
NetworkService.shared.productService.postInterest(productId: id) { [weak self] result in
switch result {
case .success:
print("좋아요 성공")
self?.isInterested = true
default:
break
}
continuation.resume()
}
}
}
print("postInterestToggle 완료")
}

그래서 정리를 하면,
withCheckedContinuation를 사용하면 기존의 콜백 방식의 비동기 코드를
async/await으로 사용할 때 의도대로 변환이 가능하다.
UI업데이트 안정성을 보장하기 위해서, 네트워크 완료 시점을 명확하게 제어 필요성도 느끼고 해결해보니 재미있었다.
현재 프로젝트내에 콜백 기반의 네트워크 로직이 쌓여있는데,
흐름제어를 명시적으로 하여서, 단계적으로 async/await으로 전환하는 것이 가독성에도 좋고
유지보수에 유리할 것 같다는 생각이 들었다.
'💻' 카테고리의 다른 글
| 앱스토어 출시 과정 (+ Identifiers ) (0) | 2025.02.10 |
|---|---|
| 문의하기, 평가하기, 공유하기, 앱정보 표시 (0) | 2025.02.06 |
| UIScrollView 콘텐츠 오른쪽 정렬하기 (1) | 2024.12.22 |
| SwiftData) FetchDescriptor 에러 (0) | 2024.12.20 |
| Tuist 기존 프로젝트에 테스트 타겟 추가 (2) | 2024.12.06 |