Swift 동시성은 async/await를 사용해 비동기 코드를 동기 코드처럼 읽히게 작성하면서도, 컴파일러가 데이터 경쟁 안전성을 강제합니다. Task는 동시 작업을 시작하고, actor는 가변 상태를 보호하며, @MainActor는 UI 코드가 메인 스레드에서 실행되도록 보장합니다.
await는 **일시 중단 지점(suspension point)**을 표시합니다. 함수는 그곳에서 멈추어 스레드를 다른 작업에 내주고, 대기하던 값이 준비되면 재개합니다. 콜백도, 스레드 블로킹도 없습니다.
func loadProfile() async throws -> Profile {
let user = try await fetchUser() // 중단, 스레드 재사용
let posts = try await fetchPosts(user) // user 확정 후 실행
return Profile(user: user, posts: posts)
}
// 동기 컨텍스트에서 비동기 작업 시작
Task {
let profile = try await loadProfile()
await MainActor.run { render(profile) } // 메인 스레드에서 UI 업데이트
}
actor는 가변 상태에 대한 접근을 직렬화합니다. 한 번에 하나의 태스크만 접근하므로 락도 없고 데이터 경쟁도 없습니다.
actor ImageCache {
private var store: [URL: Image] = [:]
func image(for url: URL) -> Image? { store[url] } // 격리됨
func insert(_ img: Image, for url: URL) { store[url] = img }
}
@MainActor
final class ViewModel: ObservableObject { // 모든 멤버가 메인 스레드에서 실행
@Published var title = ""
}
async let과 TaskGroup은 자식을 병렬로 실행하고 함께 대기합니다. 부모를 취소하면 자식도 취소됩니다.
async let a = fetchA() // 둘 다 즉시, 병렬로 시작
async let b = fetchB()
let (x, y) = try await (a, b)
@MainActor를 잊으면 "Publishing changes from background thread" 경고가 발생합니다.Task { }는 actor 컨텍스트를 상속하지만 Task.detached는 상속하지 않으므로 아껴서 사용하세요.async/await는 깊게 중첩된 완료 핸들러("콜백 지옥")를 대체했고, 이제 컴파일러가 빌드 시점에 데이터 경쟁을 잡아냅니다. 면접관은 지원자가 일시 중단 지점, actor 격리, @MainActor — 현대 iOS 동시성을 읽기 쉽고 안전하게 만드는 모델 — 을 이해하는지 확인합니다.
주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기