
본 글은 Sendable (애플 공식 문서)를 한국어로 번역하여 옮긴 글입니다.
데이터 경쟁(data race)의 위험없이 임의의 동시성 컨텍스트(context) 사이에서 값이 안전하게 공유될 수 있는 쓰레드에 안전한 타입
iOS 8.0+ | iPadOS 8.0+ | Mac Catalyst 13.0+ | macOS 10.10+ | tvOS 9.0+ | visionOS 1.0+ | watchOS 2.0+
protocol Sendable
이 타입의 값은 공유되는 가변 상태를 가지지 않거나, 해당 상태를 락(lock)이나 특정 액터(actor)만 접근하도록 강제하여 보호할 수 있습니다.
전송 가능한(sendable) 타입의 값을 하나의 동시성 도메인에서 다른 도메인으로 안전하게 전달할 수 있습니다. 예를 들어, 액터의 메서드를 호출할 때 매개변수로 전송 가능한 값을 전달할 수 있습니다. 아래의 모든 항목은 전송 가능하다고 표시될 수 있습니다.
값 타입
변경 가능한 저장소가 없는 참조 타입
내부적으로 상태에 대한 접근을 관리하는 참조 타입
(@Sendable 속성을 표시한) 함수와 클로저
비록 이 프로토콜이 요구하는 메서드나 프로퍼티가 없더라도, 컴파일 타임에 강제적으로 부여되는 의미적 요구사항이 있습니다. 이 요구사항은 아래 섹션에 나열되어 있습니다. Sendable 프로토콜은 해당 타입이 선언된 파일 내에서 준수해야 합니다.
컴파일러의 검증없이 Sendable 프로토콜을 준수하고 싶다면, @unchecked Sendable을 작성하세요. 검증하지 않는(unchecked) 전송 가능한 타입은 개발자가 락이나 큐(queue)로 해당 상태에 대한 모든 접근을 보호하는 방식으로 책임을 져야 합니다. 검증하지 않는 Sendable 프로토콜은 해당 타입이 선언된 파일 내에서 준수해야 한다는 규칙도 적용하지 않습니다.
Task가 속한 언어 수준의 동시성 모델에 대한 자세한 정보는 The Swift Programming Language 문서의 Concurrency를 참조하세요.
Sendable 프로토콜의 요구사항을 만족하려면, 구조체와 열거형은 전송 가능한 멤버나 연관 값을 가져야 합니다. 일부 경우에는, 요구사항을 만족하는 구조체나 열거형은 암시적으로 Sendable 프로토콜을 준수합니다.
확장 불가능한(@frozen) 구조체와 열거형
접근 제어 범위가 public이 아니며 @usableFromInline이 표시되지 않은 구조체와 열거형
이 경우가 아니라면, Sendable 프로토콜 준수를 명시적으로 선언해야 합니다.
전송 불가능한(non-sendable) 저장 프로퍼티를 가지는 구조체와 전송 불가능한 연관 값을 가지는 열거형은 컴파일 시간에 검증을 비활성화하는 @unchecked Sendable로 표시될 수 있으며, 이후 Sendable 프로토콜의 의미적 요구사항을 만족하는지 수동으로 검증해야 합니다.
모든 액터 타입은 암시적으로 Sendable 프로토콜을 준수합니다. 이는 액터가 자신이 가진 가변 상태에 대한 모든 접근이 순차적으로 수행된다고 보장하기 때문입니다.
클래스가 Sendable 프로토콜의 요구사항을 만족하려면
final로 표시되어야 하고
불변(immutable)이고 전송 가능한 저장 프로퍼티만을 가져야 하고
상위 클래스가 없거나 NSObject를 상위 클래스로 가져야 합니다.
@MainActor로 표시된 클래스는 암시적으로 전송 가능합니다. 이는 메인 액터(main actor)가 자신의 상태에 대한 모든 접근을 관리하기 때문입니다. 이 클래스는 가변이고 전송 불가능한 저장 프로퍼티를 가질 수 있습니다.
위 요구사항을 만족하지 못하는 클래스는 컴파일 시간에 검증을 비활성화하는 @unchecked Sendable로 표시될 수 있으며, 이후 Sendable 프로토콜의 의미적 요구사항을 만족하는지 수동으로 검증해야 합니다.
Sendable 프로토콜을 준수하는 대신에, @Sendable 속성으로 전송 가능한 함수와 클로저를 표시할 수 있습니다. 함수와 클로저가 캡처(capture)하는 모든 값은 전송 가능해야 합니다. 추가로, 전송 가능한 클로저는 오직 값으로 캡처(by-value capture)해야 하며, 캡처된 값은 전송 가능한 타입이어야 합니다.
예를 들어, Task.detached(priority:operation:) 메서드를 호출할 때와 같은 상황에서 전송 가능한 클로저가 요구됩니다. 해당 요구사항을 만족하는 클로저는 암시적으로 Sendable 프로토콜을 준수하게 됩니다.
타입 어노테이션의 한 부분으로 @Sendable을 적거나, 클로저의 매개변수 앞에 @Sendable을 적어 클로저가 전송 가능하다고 명시적으로 표시할 수 있습니다. 예를 들어,
let sendableClosure = { @Sendable (number: Int) -> String in
if number > 12 {
return "More than a dozen"
} else {
return "Less than a dozen"
}
}
Sendable 프로토콜의 요구사항을 만족하려면, 튜플의 모든 요소가 전송 가능해야 합니다. 해당 요구사항을 만족하는 튜플은 암시적으로 Sendable 프로토콜을 준수하게 됩니다.
Int.Type과 같은 메타 타입은 암시적으로 Sendable 프로토콜을 준수합니다.