티스토리 뷰

728x90
반응형

 

- [Swift] Sendable 을 먼저 읽고 오시길 추천드립니다. 

- Swift 6 기반의 글입니다.


[1] @unchecked

 

GPT 의 설명

Swift에서는 Sendable이라는 프로토콜을 통해 값이 스레드 간 안전하게 공유될 수 있는지를 나타내는데, 기본적으로 Sendable 프로토콜을 구현한 타입은 스레드 안전해야 합니다. 하지만, @unchecked를 사용하면 이 안전성 검사를 생략하고 강제로 Sendable을 준수하는 것으로 표시할 수 있습니다.


예를 들어, @unchecked Sendable을 사용하면 Swift 컴파일러는 이 타입을 Sendable로 인식하지만, 실제로는 스레드 안전하지 않을 수 있음을 경고 없이 허용합니다.

 

struct SomeType: @unchecked Sendable {
    // 스레드 안전하지 않은 코드가 포함될 수 있음
}

 


이 속성은 타입이 Sendable 프로토콜을 준수해야 하는 상황에서만 사용됩니다. 

강제로 스레드 안전성을 우회하려는 경우에 사용하며, 이로 인해 발생할 수 있는 경쟁 상태나 안전성 문제는 개발자가 책임져야 합니다.

 

 

공식 문서

 

# Sendable

To declare conformance to Sendable without any compiler enforcement, write @unchecked Sendable. You are responsible for the correctness of unchecked sendable types, for example, by protecting all access to its state with a lock or a queue

 

 

궁금

Q. enum, struct, class 말고 function이나 closure 에도 적용할 수 있나 ?  -> 안된다. 

 

 

 

 

Q. protocol 은 ? -> 안된다

 

 

 

대신 이런 식으로는 에러 해결할 수 있다. (좋은 방법 X) 

 

 

 

 

Q. 암묵적으로 Sendable 을 conform 하고 있는 actor 에도 쓸 수 있나 ? -> 일단 컴파일 에러는 안난다. 근데 이렇게 쓸 일 없으니 안 궁금해도 된다. 

 

 

 

 

[2] @preconcurrency

 

GPT 의 설명

@preconcurrency는 기존 비동기 코드가 도입된 코드가 새로운 concurrency 시스템과 호환되도록 강제하는 데 사용됩니다. 이 속성은 특히 이전 버전의 코드에서 Sendable이나 다른 concurrency 관련 검사를 피하기 위해 사용되며, 기존 코드가 새로운 concurrency 시스템을 알지 못하고 작성되었음을 나타냅니다.


예를 들어, @preconcurrency는 concurrency 시스템이 없던 Swift 5.5 이전에 작성된 코드에서 사용할 수 있으며, 해당 코드가 concurrency 관련 새로운 규칙을 준수하지 않아도 되도록 허용합니다.

 

@preconcurrency protocol OldProtocol {
    // concurrency가 없던 시점의 프로토콜 정의
}

 

 

공식 문서

 

swift-6-concurrency-migration-guide

You can stage in diagnostics caused by adding global actor isolation on a protocol using @preconcurrency. This will preserve source compatibility with clients that have not yet begun adopting concurrency.

@preconcurrency @MainActor
protocol Styler {
    func applyStyle()
}

 

 

SE-0337 Incremental migration to concurrency checking

 

When applied to a nominal declaration, the @preconcurrency attribute indicates that a declaration existed before the module it belongs to fully adopted concurrency, so the compiler should take steps to avoid these source and ABI breaks. It can be applied to any enum, enum case, struct, class, actor, protocol, var, let, subscript, init or func declaration.

 

 

 

단순히 modern concurrency 준비 안된 외부 모듈 import 할 때만 쓰는 거라고 알고 있었는데, 

import 문 외에도 쓸 수 있다는 것을 최근 알았다 ;;;;  actor 에도 붙일 수 있다니...

 

 

예제 (내부 모듈에서 쓰는)

SomeStruct 를 Sendable 로 만들고 싶지만, 내부 필드가 Sendable 준비가 안된 상태 일 때 

 

 

 

@preconcurrency 를 붙여 에러를 워닝으로 전환가능 

 

 

 

만약 @unchecked 쓰면 워닝도 안나오게 할 수 있음 

 

 

 

이런 혼합도 문법적으로는 가능하고

 

 

@preconcurrency 를 뒤로 보내면 워닝을 볼 수 있다. 

 

 

actor 에 @preconcurrency 붙였을 때도, 위와 동일한 워닝이 발생해야할 것 같아서 테스트해보니

@preconcurrency 위치에 따라 워닝 여부가 다르다 ;;

 

 

 

 

@unchecked vs @preconcurrency (GPT) 

- @unchecked는 타입이 스레드 안전성을 검사하지 않고 Sendable을 준수한다고 선언할 때 사용합니다.

- @preconcurrency는 concurrency 이전에 작성된 코드와 호환성을 유지하면서 concurrency 검사를 피하고자 할 때 사용합니다.


두 속성 모두 concurrency와 관련이 있지만, @unchecked는 주로 스레드 안전성 검사 생략에, @preconcurrency는 기존 코드와의 호환성 유지에 사용된다는 점에서 차이가 있습니다.

 

 

 

[3] @retroactive 

 

공식문서

#  Retroactive Sendable Conformance (swift 6 migration guide)

 

Your dependencies may also expose types that are using manual synchronization. This is usually visible only via documentation. It is possible to add an @unchecked Sendable conformance in this case as well.

extension ColorComponents: @retroactive @unchecked Sendable {
}

 

# SE-0364 Warning for Retroactive Conformances of External Types

 

 외부 모듈에서 가져온 타입을 extension 해서 쓰는 경우가 있다.

// Not a great implementation, but I suppose it could be useful.
extension Date: Identifiable {
    public var id: TimeInterval { timeIntervalSince1970 }
}

 

이는 여러 사이드이펙 가능성을 안고 있다. 예를들어 Foundation 이 나중에 id 를 제공하면 빌드가 실패할 것, Foundation 에서 제공하는  id (다른 구현)을 선택했는데,  이미 DB 에 저장된 ID 가 있다면 ID 는 다른 값이 되는 등..  (특히 라이브러리라면 라이브러리 쓰는 모든 클라이언트에 전파될 것이므로 더 치명적) 

 

따라서 이 패턴을 문제로 보고 명시적으로 경고로 표시하는 게 좋다. 

 

부득이한 경우, 클라이언트는 @retroactive attribute 를 프로토콜에 추가하여 이 경고를 무시할 수 있다. 

 

 

궁금

Q. 내부 모듈 extension 에 쓰면 에러나 워닝 발생하는가 ? -> 에러 발생 

 

 

 

 

반응형

'🍏 > Swift' 카테고리의 다른 글

[Swift] Noncopyable (~Copyable)  (3) 2024.10.26
[Swift] Typed throws  (0) 2024.10.13
[Swift] AsyncStream  (1) 2024.08.24
[Swift] @TaskLocal  (0) 2024.08.23
[Swift] @dynamicCallable 유용한 예제 모음  (4) 2024.03.16
댓글