BIBI BLOG
Swift 6의 새로운 동시성(Concurrency) 기능 이해하기 🚀 본문
Swift 6의 새로운 동시성(Concurrency) 기능 이해하기 🚀
Swift 6에서는 동시성 관련 기능이 더욱 강화되었습니다! 이제 UI 업데이트를 더 안전하게 관리하고, 데이터 경쟁 상태(Data Race)를 방지하며, 코드의 안정성을 높일 수 있습니다. 하지만 기존 코드를 Swift 6에 맞게 업데이트하려면 몇 가지 변경이 필요합니다.
이 글에서는 Swift 6의 새로운 동시성 기능과 기존 코드에서 발생할 수 있는 경고 및 해결 방법을 쉽고 자세히 설명하겠습니다. 😊
1. Swift 6 동시성의 주요 변화
Swift 6에서는 코드를 더욱 안전하게 실행하기 위해 동시성 검사를 엄격하게 강화했습니다.
아래와 같은 주요 변화가 있습니다.
✅ UI 업데이트를 더 엄격하게 관리 (@MainActor 적용 필수)
✅ 함수와 속성에서 명확한 동시성 선언 필요 (예: @MainActor, @Sendable)
✅ 글로벌 상태(Global State) 관리 개선 (@globalActor 활용 가능)
✅ 경고 메시지 개선 (스레드 안전하지 않은 코드 감지 가능)
2. Xcode 16으로 업그레이드할 때 발생하는 문제와 해결법
📌 예제 1: UI 업데이트 시 @MainActor를 명시적으로 사용해야 함
🚨 문제:
@MainActor를 사용하지 않고 UI를 업데이트하면, Swift 6에서는 경고가 발생합니다.
❌ 수정 전 (경고 발생 코드)
class ProfileViewModel: ObservableObject {
@Published var title: String = ""
func loadData() async {
let data = await fetchData()
title = data.title // ❌ 경고: Main 스레드에서 실행되지 않음!
}
}
✅ 수정 후 (@MainActor 추가)
@MainActor // ✅ ViewModel 전체를 MainActor에서 실행되도록 지정
class ProfileViewModel: ObservableObject {
@Published var title: String = ""
func loadData() async {
let data = await fetchData()
title = data.title // ✅ 이제 안전한 UI 업데이트 가능!
}
}
- @MainActor를 클래스에 추가하면, 해당 클래스의 모든 코드가 메인 스레드에서 실행됨.
- UI 업데이트는 항상 메인 스레드에서 실행해야 안전하므로 Swift 6에서는 이를 강제함.
📌 예제 2: DispatchQueue 대신 MainActor.run 사용하기
Swift 5에서는 UI 업데이트를 위해 DispatchQueue.main.async를 사용했어요. 하지만, Swift 6에서는 더 안전한 MainActor.run을 사용해야 해요.
❌ 수정 전 (DispatchQueue 사용)
func updateUI() {
DispatchQueue.main.async { // ❌ 경고: DispatchQueue 대신 MainActor.run을 사용할 것
self.label.text = "안녕하세요!"
}
}
✅ 수정 후 (MainActor.run 사용)
func updateUI() async {
await MainActor.run { // ✅ MainActor.run을 사용하여 UI 업데이트
self.label.text = "안녕하세요!"
}
}
📝 설명:
- DispatchQueue.main.async를 사용하면 메인 스레드에서 실행됨을 보장할 수 없음.
- await MainActor.run을 사용하면, Swift가 메인 스레드에서 실행됨을 보장하여 더 안전함.
📌 예제 3: 여러 스레드에서 공유되는 데이터 보호하기 (UserDefaults 예제)
공유 상태를 여러 스레드에서 동시에 접근하면 데이터 충돌이 발생할 수 있어요.
❌ 수정 전 (경고 발생)
class SettingsManager {
static let shared = SettingsManager()
var theme: String = "light" // ❌ 경고: 다중 스레드에서 충돌 가능
}
✅ 수정 후 (Global Actor로 보호)
@globalActor
struct SettingsActor {
actor ActorType { }
static let shared = ActorType()
}
@SettingsActor // ✅ Custom Global Actor로 보호
class SettingsManager {
static let shared = SettingsManager()
var theme: String = "light" // ✅ 이제 안전한 데이터 관리 가능!
}
📝 설명:
- @globalActor를 사용하면 이 클래스가 특정 스레드에서만 실행되도록 강제할 수 있음.
- 이를 통해 데이터 충돌(Data Race) 문제를 해결할 수 있음.
3. 가장 많이 발생하는 경고와 해결법
Swift 6에서는 동시성과 관련된 새로운 경고가 많이 발생합니다. 대표적인 사례와 해결법을 알아볼게요.
🚨 경고 1: Non-Sendable 타입을 @MainActor에서 사용하려고 할 때
❌ 경고 메시지:
"Non-sendable type 'ViewController' passed in implicitly asynchronous call to main actor-isolated method"
✅ 해결 방법:
class ViewController: UIViewController {
func onButtonTap() {
Task { @MainActor in // ✅ MainActor에서 실행
self.updateUI()
}
}
@MainActor
func updateUI() { ... }
}
🚨 경고 2: @Sendable 클로저에서 self를 참조할 때
❌ 경고 메시지:
"Capture of 'self' with non-sendable type 'MyClass' in a @Sendable closure"
✅ 해결 방법 (weak self 사용)
Task { [weak self] in // ✅ weak self로 참조하여 메모리 누수 방지
guard let self else { return }
await self.fetchData()
}
🚨 경고 3: Non-Sendable 타입을 동시성 컨텍스트에서 사용하려고 할 때
❌ 경고 메시지:
"Function cannot be marked as '@Sendable' due to non-sendable parameter of type 'DataModel'"
✅ 해결 방법 (Sendable 프로토콜 적용)
struct DataModel: Sendable { // ✅ Sendable 적용
let id: UUID
let value: String
}
📝 설명:
- Sendable을 적용하면, 데이터 모델이 여러 스레드에서 안전하게 공유될 수 있도록 보장함.
4. Swift 6에서 동시성을 디버깅하는 방법
Xcode 16에서는 동시성 문제를 더 쉽게 찾을 수 있도록 강력한 디버깅 도구를 제공합니다.
✅ 1. Thread Sanitizer(TSan) 활성화하기
데이터 경쟁(Data Race) 문제를 찾으려면?
🔹 Xcode 메뉴에서 Product > Scheme > Edit Scheme > Run > Diagnostics > Thread Sanitizer 활성화
✅ 2. Task Tracing 활용하기
비동기 작업이 어떻게 실행되는지 추적하려면?
await withTaskTracing {
await fetchUserData()
}
✅ 3. -strict-concurrency 컴파일러 플래그 활성화
Swift 6의 엄격한 동시성 검사를 사용하려면?
🔹 Build Settings > SWIFT_STRICT_CONCURRENCY = complete 설정
Swift 6 동시성을 쉽게 적용하는 방법
✅ UI 업데이트는 @MainActor를 적극적으로 사용
✅ DispatchQueue 대신 MainActor.run 활용
✅ 공유 데이터는 @globalActor로 보호
✅ 동시성 오류는 Thread Sanitizer로 검사
✅ Sendable을 점진적으로 도입하여 최적화
'iOS > Swift' 카테고리의 다른 글
Swift Style Guide: 애플 스타일로 작성하는 방법:Part 2📝 (0) | 2025.02.28 |
---|---|
Swift Style Guide: 애플 스타일로 작성하는 방법:Part 1📝 (1) | 2025.02.26 |
SwiftUI가 Struct를 사용하여 뷰를 정의하는 이유 (0) | 2025.02.22 |
[Swift] @frozen 속성: 더 안정적이고 빠른 코드 만들기 (0) | 2025.02.20 |
[Swift 6.0] Protocol Extensions: 더 강력해진 POP 🚀 (0) | 2025.02.18 |