지난 번 포스팅에서 @Sendable에 대해 알아보기 위해서 @Sendable이 존재하는 이유인 Race Condition에 대해서 알아봤습니다. 이번 포스팅에서는 Sendable protocol에 대해서 알아봅니다.
Sendable | Apple Developer Documentation
위 공식문서의 정의를 보면 복사를 통해서 동시성 영역 (= 다른 쓰레드)에 안전하게 전달할 수 있는 값을 가진 타입이라고 합니다. 즉 reference를 전달하는 것이 아니라 value를 전달해야지만 안전할 수 있다는 것이죠. 하지만 이 protocol을 채택하기 위해서 반드시 reference type이어야 하는 것은 아닙니다.
마찬가지로 공식문서입니다. Sendable을 채택할 수 있는 타입들입니다. value 타입은 당연히 가능합니다. 다만 struct의 경우 모든 member들이 Sendable해야 하고 enum의 associated value도 마찬가지입니다.
class와 같은 Reference type도 Sendable이 될 수 있지만 mutable해서는 안됩니다.
다만 mutable한 Reference type 중에 상태에 대한 접근을 내부적으로 통제할 수 있는 reference 타입은 가능합니다. 예를 들면 직접 property를 업데이트를 허용하지는 않고 반드시 method를 통해 업데이트하도록 하는데 그 method가 Race condition을 일으키지 않는 경우입니다. (말로만 설명하니까 어렵네요…)
특히 actor라는 타입을 활용하면 쉽게 상태에 대한 접근을 내부적으로 통제할 수 있는 reference 타입을 만들 수 있습니다. 나중에 포스팅을 통해서 소개하도록 할께요!
마지막으로 우리가 알아보고 있는 functions 와 closures에 대한 내용입니다. 기본적으로 함수(클로저)는 reference 타입입니다. 하지만 함수(클로저)는 프로토콜을 채택할 수 없습니다. 따라서 @Sendable attribute를 사용해서 Sendable임을 선언합니다.
함수(클로저)가 Sendable하기 위해서는 켭쳐하는 타입들이 (= 파라미터)가 전부 Sendable이어야 하고 value 방식으로 전달되어야 합니다. (복사)
struct WeatherClient {
var forecast: @Sendable (GeocodingSearch.Result) async throws -> Forecast
var search: @Sendable (String) async throws -> GeocodingSearch
}
제가 애초에 이 포스팅을 작성하기 시작한 이유는 위 클로저들 앞에 각각 붙은 @Sendable의 정체를 밝혀내기 위해서 였습니다.
각각의 클로저는 다른 스레드로 보내서 실행될 수 있도록 하기 위해서 @Sendable attribute가 붙은 것이죠. WeatherClient에 정의된 각각의 클로저는 네트워크 통신을 하는 클로저이기 때문에 메인 스레드를 잡아 두기 보다는 다른 스레드로 보내는 것이 합리적이기 때문입니다.
위에서 설명한 정의에 의하면 위 클로저들이 캡쳐하는 타입들도 전부 Sendable이어야 합니다.
이제 @Sendable의 정체는 알았습니다. 하지만 아직 이 시리즈는 끝나지 않았는데요. Sendable을 공부하면서 알게된 actor라는 타입에 대해서 다음 포스팅에서부터 알아보도록 하겠습니다.