https://developer.apple.com/documentation/swift/sendable/
Sendable | Apple Developer Documentation
A thread-safe type whose values can be shared across arbitrary concurrent contexts without introducing a risk of data races.
developer.apple.com
Sendable
Sendable은 Swift Concurrency 환경에서 여러 스레드나 액터 간에 안전하게 값을 전달할 수 있음을 보장하기 위한 프로토콜이다. 이는 데이터 경합(data race)과 관련된 문제를 방지하고, 동시성 안전성을 확보하는데 중요한 역할을 한다.
Sendable은 타입이 다른 스레드나 액터로 안전하게 전달될 수 있음을 컨파일러에 알려주는 마커 프로토콜이다.
이를 통해 값이 한 스레드에서 수정되다가 다른 스레드에서 읽힐때 발생할 수 있는 데이터 경합 문제를 방지할 수 있다.
일반적으로, Sendable로 채택된 타입은 내부 상태가 불변이거나 변경이 안전하게 이루어지도록 설계되어있어야 한다.
예를 들어 Swift의 기본 값 타입(Int, String, Array 등)은 값 타입 이므로 기본적으로 Sendable로 간주된다.
Swift Concurrency와 Sendable
구조적 동시성(Structured Concurrency) :
Swift Concurrency에서는 여러 작업(Task)과 액터 간의 값 전달이 빈번하게 발생한다. Sendable은 이 값이 안전하게 전송되도록 보장한다.
컴파일러의 역할 :
컴파일러는 Sendable 프로토콜에 맞지 않는 타입이 동시성 경계를 넘어서 전달되는 경우, 경고나 에러를 발생시킨다. 이를 통해 개발자는 잠재적인 동시성 버그를 미연에 방지할 수 있다.
액터 메서드나 비동기 함수의 매개변수, 반환값 등에 전달되는 값은 Sendable이어야 한다. 만약 Sendable이 아닌 타입이 사용 된다면, 컴파일러는 안전하지 않은 동시성 데이터 접근을 감지하고 이를 알려준다.
Sendable 채택 방법
대부분의 값 타입(구조체, 열거형 등)은 모든 저장 프로퍼티가 Sendable이면 자동으로 Sendable로 간주된다. 만약 직접 만든 타입이 동시성 안전성을 보장한다면, 해당 타입에 Sendable을 채택한다고 명시할 수 있다.
struct UserData: Sensdable {
let id: Int
let name: String
}
클래스는 참조 타입이므로, 단순히 Sendable을 채택하는 것만으로 충분하지 않다. 클래스의 내부 상태가 동시성에 안전하도록 설계되어야 하고 보통 액터를 통해 관리하는 것이 일반적이다.
Sendable과 관련된 주의사항
클로저 캡쳐 :
비동기 함수나 액터 간에 클로저가 캡쳐하는 값들도 Sendable해야 한다. 그렇지 않으면 컴파일러가 경고를 발생시키기 때문
타입 안전성 :
Sendable을 채택한 타입이 정말로 동시성 안전한지 확인해야한다. 단순히 프로토콜을 채택하는 것만으로는 내부 동작까지 보장되지 않으며, 불변성을 유지하거나 동기화 매커니즘을 사용하는 등의 추가 노력이 필요할 수 있다.
전환 및 상속 :
만약 기존에 작성한 타입이 Sendable 요구사항을 충족하지 않는다면, 동시성 환경으로 전환할 때 해당 타입을 수정하거나, 필요한 경우 별도의 동기화 코드를 추가해야한다.
비동기 작업이나 동시성 경계를 넘어서 실행되는 클로저의 경우, 캡처하는 값들이 Sendable해야한다. 이때 클로저에 @Sendable 어노테이션을 붙여 사용하게 된다
func processData(value: Int, completion: @Sendable (Int) -> Void) {
Task {
// 비동기 작업 수행
let result = value * 2
completion(result)
}
}
이 예제에서 completion 클로저는 @Sendable로 선언되어 클로저 내부에서 캡처되는 모든 값들이 동시성 안전하다는 것을 보장한다!
다음은 복합 타입 내부에 Sendable 요소가 포함되어있는 형태를 봐보자!
구조체를 만들때 그 내부에 배열이나 다른 구조체가 포함된다면, 이 모든 구성 요소들이 Sendable 이어야 한다.
struct User: Sendable {
let id: Int
let name: String
}
struct ChatRoom: Sendable {
// 배열도 구조체 배열인 경우, 배열의 요소(User)들이 Sendable이면 자동으로 Sendable로 간주됨
let participants: [User]
let roomName: String
}
이렇게 구성된 ChatRoom 타입은 동시성 경계를 넘어 안전하게 전달할 수 있다.
이렇게 Sendable의 개념에 대해서 알아보았다 아직 완벽하게 이해하려면 조금 더 사용해보고 다시 공부해야할 것 같다 :0 공부는 해도 해도 끝이없네~
'◽️ Programming > iOS' 카테고리의 다른 글
Static Dispatch & Dynamic Dispatch (1/2) (0) | 2025.02.28 |
---|---|
Swift Concurrency에서 Task는 어떤 역할을 담당하나 (0) | 2025.02.20 |
Objective-C를 Swift에 가져와 사용하기 (0) | 2025.02.12 |
Swift Concurrency 중 MainActor의 역할은 무엇인가 (0) | 2025.02.03 |
Vision 프레임 워크를 활용해 얼굴 인식하기 (0) | 2025.01.20 |