[iOS] Async/Await
2025. 2. 6. 20:12ㆍiOS
반응형
Swift의 async/await는 비동기 작업을 더 쉽게 작성하고 관리할 수 있도록 도와주는 기능입니다. 기존의 콜백 기반 비동기 코드보다 가독성이 좋고, 오류 처리도 간편하게 할 수 있습니다.
1. async와 await란?
- async : 비동기 함수(메서드)를 정의할 때 사용합니다.
- await : async 함수 내부에서 비동기 작업이 완료될 때까지 기다리는 키워드입니다.
기존 클로저 기반 비동기 코드와 비교하면 가독성이 훨씬 좋아집니다.
📌 기존 콜백 방식 (Completion Handler)
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
sleep(2) // 네트워크 요청 시뮬레이션
completion("데이터 로드 완료")
}
}
fetchData { result in
print(result) // "데이터 로드 완료"
}
✅ async/await 방식
func fetchData() async -> String {
sleep(2) // 네트워크 요청 시뮬레이션
return "데이터 로드 완료"
}
Task {
let result = await fetchData()
print(result) // "데이터 로드 완료"
}
2. async 함수 선언 및 사용
async 함수는 await을 사용하여 호출해야 합니다.
func doSomething() async {
print("작업 시작")
await Task.sleep(2_000_000_000) // 2초 대기
print("작업 완료")
}
// Task를 사용하여 실행
Task {
await doSomething()
}
- Task.sleep(_:)은 비동기 함수에서 일정 시간 동안 대기하도록 하는 방법입니다.
- Task {} 내에서 await을 사용하여 비동기 함수를 호출할 수 있습니다.
3. async와 DispatchQueue.global().async의 차이점
비교항목async/awaitDispatchQueue.global().async
가독성 | 좋음 | 비교적 복잡함 |
오류 처리 | try await로 처리 | do-catch + completion handler 필요 |
컨텍스트 유지 | Swift 런타임이 적절한 스레드에서 실행 | 개발자가 직접 GCD 사용 |
백그라운드 실행 | Task {} 또는 Task.detached {} 사용 | DispatchQueue.global().async 사용 |
예제:
// GCD 방식
DispatchQueue.global().async {
print("백그라운드 작업 수행 중")
}
// async/await 방식
Task {
print("백그라운드 작업 수행 중")
}
4. Task와 Task.detached
Task {}: 기존 컨텍스트를 유지
Task {
print("Task 내부 실행")
}
- 부모 태스크의 컨텍스트를 상속받음 (예: UI 관련 작업 시 유용)
Task.detached {}: 독립적인 실행
Task.detached {
print("Detached Task 실행")
}
- 기존 컨텍스트와 상관없이 별도로 실행됨
- 네트워크 작업과 같은 독립적인 작업에 적합
5. async와 throws 함께 사용하기
비동기 함수에서 오류가 발생할 경우 throws와 함께 사용할 수 있습니다.
enum NetworkError: Error {
case failed
}
func fetchData() async throws -> String {
let success = Bool.random()
if success {
return "데이터 로드 성공"
} else {
throw NetworkError.failed
}
}
Task {
do {
let result = try await fetchData()
print(result)
} catch {
print("에러 발생: \(error)")
}
}
- try await을 사용하여 오류 처리를 수행할 수 있습니다.
6. async let으로 동시 실행
여러 개의 비동기 작업을 동시에 실행할 때 async let을 사용할 수 있습니다.
func fetchUserProfile() async -> String {
sleep(2)
return "사용자 프로필"
}
func fetchUserPosts() async -> String {
sleep(3)
return "사용자 게시글"
}
Task {
async let profile = fetchUserProfile()
async let posts = fetchUserPosts()
let result = await "\(profile), \(posts)"
print(result) // "사용자 프로필, 사용자 게시글" (약 3초 후 출력)
}
- async let을 사용하면 병렬 실행이 가능하여 성능이 향상됩니다.
- await을 사용하면 모든 작업이 완료될 때까지 기다립니다.
7. @MainActor와 await MainActor.run
비동기 작업 후 UI 업데이트를 위해 @MainActor를 사용할 수 있습니다.
@MainActor
class ViewModel {
var text: String = ""
func fetchData() async {
let result = await fetchDataFromNetwork()
text = result // UI 업데이트
}
}
또는 특정 코드 블록에서 메인 스레드에서 실행하도록 강제할 수도 있습니다.
Task {
let data = await fetchDataFromNetwork()
await MainActor.run {
// UI 업데이트
print("UI 업데이트: \(data)")
}
}
8. withCheckedContinuation으로 기존 콜백 함수 감싸기
기존 콜백 기반의 API를 async/await으로 변환할 수도 있습니다.
func fetchDataWithCallback(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
sleep(2)
completion("데이터 로드 완료")
}
}
// async/await 변환
func fetchData() async -> String {
await withCheckedContinuation { continuation in
fetchDataWithCallback { result in
continuation.resume(returning: result)
}
}
}
Task {
let result = await fetchData()
print(result) // "데이터 로드 완료"
}
- withCheckedContinuation을 사용하면 기존 비동기 API를 쉽게 변환할 수 있습니다.
9. actor와 async를 사용한 스레드 안전성 확보
actor를 사용하면 동시 접근으로 인한 문제를 방지할 수 있습니다.
actor Counter {
private var value = 0
func increment() {
value += 1
}
func getValue() -> Int {
return value
}
}
let counter = Counter()
Task {
await counter.increment()
print(await counter.getValue()) // 1
}
- actor 내부의 변수는 자동으로 스레드 안전하게 보호됩니다.
- await을 사용하여 actor에 접근합니다.
정리
기능설명
async | 비동기 함수 선언 |
await | 비동기 함수 호출 시 사용 |
Task {} | 비동기 코드 실행 (컨텍스트 유지) |
Task.detached {} | 독립적인 비동기 실행 |
throws | 오류를 던질 수 있는 비동기 함수 |
async let | 동시 실행 최적화 |
@MainActor | UI 업데이트 시 사용 |
withCheckedContinuation | 기존 콜백을 async/await으로 변환 |
actor | 스레드 안전한 상태 관리 |
async/await을 활용하면 코드 가독성과 유지보수성이 높아지고, Swift의 동시성 지원을 최대로 활용할 수 있습니다! 🚀
반응형
'iOS' 카테고리의 다른 글
[iOS] CryptoKit vs. CryptoSwift (0) | 2025.02.14 |
---|---|
[iOS] WKWebView Cookie (1) | 2025.02.11 |
[iOS] 무결성 (Integrity) (3) | 2025.02.06 |
[iOS] ILClassificationResponse (1) | 2025.02.03 |
[iOS] Performance Trace란? (0) | 2025.02.01 |