Boost‐SwiftUI‐2024.03.04(화).md - BoostSwiftUI/SwiftUI GitHub Wiki
원본 텍스트 파일
Boost-SwiftUI-2024.03.04(화).txt
스터디 시간 및 참여자
- 2025.03.04 화 오후 9:02 ・ 99분 56초
- 고병학 권승용 유정주 윤동주 이창준 정종인
- 클로버노트를 이용해 회의 내용을 기록하고, Claude를 이용해 요약, 편집했습니다.
iOS 동시성(Concurrency) 및 Swift 개발 심층 탐구
Swift 동시성의 이해
Actor와 Dispatch Queue의 관계
- Swift 동시성에서 Actor와 기존 Dispatch Queue는 완전히 다른 개념으로 분리하여 접근해야 함
- Actor는 데이터 경쟁 상태(Data Race)를 방지하기 위한 타입 시스템 차원의 보호 메커니즘을 제공
- Dispatch Queue는 작업을 특정 스레드에 할당하는 기능을 중점적으로 제공
- 두 개념을 혼합해서 사용할 경우 예상치 못한 동작이 발생할 수 있음
- 예: Task 내부에서 DispatchQueue.main을 사용하여 UI 업데이트 시 타이밍 이슈 발생 가능성 있음
Main Actor의 특성
- Main Actor는 UI 관련 작업이 항상 메인 스레드에서 실행되도록 보장함
- SwiftUI의 View는 '@MainActor'에서 수행되어야 함
- UIKit 관련 코드도 메인 스레드에서 실행되어야 함
- Main Actor는 Global Actor의 특별한 형태
- 시리얼 실행자(Serial Executor)를 사용하여 메인 스레드에서 작업을 순차적으로 처리
- 내부적으로
enqueueOnMain
함수를 사용하여 메인 스레드에 작업을 전달
Global Actor 및 스레드 관리
- Main Actor가 아닌 모든 Actor는 공유된 글로벌 동시성 스레드 풀(Shared Global Concurrency Thread Pool)을 사용
- 이는 DispatchQueue.global과 유사한 개념으로 이해할 수 있음
- 메인 스레드가 아닌 백그라운드 스레드에서 작업이 실행됨
- 커스텀 Serial Executor를 지정하면 특정 스레드나 Dispatch Queue에서 실행되도록 설정 가능
- 기본적으로는 시스템이 최적화된 방식으로 스레드를 할당
동시성 문제와 해결책
데이터 공유와 데이터 레이스
- 공유 가능한 변경 가능 상태(Mutable Shared State)는 Actor로 캡슐화하고 Sendable로 데이터를 전달해야 함
- 이는 Swift 6에서 더욱 강조되는 설계 원칙
- Actor 간의 통신은 Sendable 타입을 통해 안전하게 이루어짐
- Swift의 Dictionary는 스레드 안전(Thread-safe)하지 않음
- 여러 스레드에서 같은 Dictionary에 접근하면 해시 충돌이나 데이터 불일치 문제 발생 가능
- 캐시 구현 등에서 Actor를 활용하여 스레드 안전성 확보 가능
실제 사례: UI 버그 해결
- 실제 사례에서 채팅 말풍선의 라운딩이 일관되지 않게 표시되는 문제 발생
- 말풍선 표시는 Swift Concurrency로 처리되나 특정 라운딩 처리는 DispatchQueue.main으로 구현
- 약 0.1초의 타이밍 차이로 시각적 불일치 발생
- 모든 로직을 Swift Concurrency로 통일하여 문제 해결
- 동일한 동시성 패러다임 내에서 일관성 있게 구현하는 것이 중요
비동기/동기 호출 선택
- DispatchQueue.sync(on: .main) 사용은 메인 스레드를 블록하여 행(Hang) 현상 유발 가능
- 특히 많은 작업을 동기적으로 처리할 경우 문제 발생
- 가능한 경우 비동기 처리를 활용하여 스레드 블로킹 방지
- 예: 파일 압축 해제나 다운로드 작업에서는 비동기 처리가 적합
Swift 6와 미래 대응
Swift 6 호환성 준비
- Swift 6에서는 동시성 체킹이 컴파일 타임에 더 엄격하게 이루어짐
- Actor와 Sendable을 중심으로 한 설계가 권장됨
- 기존 코드베이스 마이그레이션 전략
- 가능한 경우 Swift Concurrency 기반으로 점진적 전환
- 실제 재설계가 필요한 부분 평가
컴바인 및 반응형 프로그래밍과의 통합
- 컴바인이나 RxSwift와 Swift Concurrency 함께 사용하기
- 컴바인은 값 전달이 클로저를 통해 이루어지므로 Sendable 고려 필요
- Continuation을 활용하여 두 패러다임 간 자연스러운 전환 가능
- 예:
receive(on:)
대신 Task와 Continuation 활용
프로젝트 구조 권장사항
- 뷰모델은 Swift Concurrency로 구현하고, UI 업데이트는 구분된 흐름으로 관리
- 뷰모델: Actor 기반 구현
- 뷰: Main Actor에서 이벤트 수신 및 처리
- 전체 프로젝트에서 일관된 동시성 패러다임 사용하기
- 한 프로젝트 내에서 여러 동시성 패턴 혼용 지양
부록: 개발 도구 및 디버깅 팁
인스트루먼트 활용법
- 스레드 상태 및 실행 흐름 분석
- 'Time Profiler'를 통해 각 스레드의 CPU 사용률 및 블로킹 확인
- 행(Hang) 현상 발생 시 진단 방법
- 메인 스레드가 블록된 경우와 바쁜 경우를 구분하여 대응
애플 공식 문서 참고사항
- Actor와 관련된 공식 문서 링크
- Swift 공식 문서에서 Actor, Sendable, Main Actor 관련 섹션 참조 권장
- 스레드 안전성 관련 깊이 있는 이해를 위한 추가 자료
- Dictionary의 스레드 안전성 이슈에 대한 Swift GitHub 저장소 참고