[SC] 전송 가능

발행: (2026년 3월 17일 AM 05:42 GMT+9)
9 분 소요
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll keep the source link unchanged and translate the rest into Korean while preserving all formatting, markdown, and technical terms.

질문

왜 컴파일러는 값이 스레드‑안전인지 알아야 할까요?

컴파일러는 값이 격리 도메인 간에 이동될 때 데이터 레이스가 발생하지 않도록 보장해야 합니다. 값이 안전하지 않다면, 컴파일러는 비결정적인 동작을 방지하기 위해 경고나 오류를 발생시킵니다.

isolation domain 이란 무엇이며, 무엇에 사용되나요?

격리 도메인은 데이터 레이스 위험 없이 값이나 참조에 접근할 수 있는 경계를 정의합니다. 종류는 다음 세 가지가 있습니다:

유형설명
nonisolated기본 도메인; 동시성 제한을 적용하지 않습니다.
actor각 액터 인스턴스마다 고유한 도메인을 가집니다.
global actor여러 타입, 프로퍼티, 함수가 공유하는 도메인 (예: @MainActor).

nonisolated 코드가 다른 도메인의 상태에 대해 갖는 제한은 무엇인가요?

  • nonisolated는 기본 격리 도메인이며 내부 동시성 제한이 없습니다.
  • 같은 타입의 다른 코드의 상태는 자유롭게 수정할 수 있습니다.
  • 다른 격리 도메인의 상태는 수정할 수 없습니다.

상태가 없는 메서드 예시 (어떤 스레드에서도 호출 가능):

// ⚠️ `nonisolated`는 기본 도메인이므로 중복됩니다.
nonisolated func add(a: Int, b: Int) -> Int {
    a + b
}

func add(a: Int, b: Int) -> Int {
    a + b
}

왜 액터의 프로퍼티에 외부에서 접근하려면 await가 필요한가요?

actor는 모든 저장 프로퍼티와 메서드가 단일 스레드 환경에서 안전하게 실행되도록 보장하여 데이터 레이스를 방지합니다.
다른 도메인에서 해당 데이터를 접근하려면 await가 필요합니다:

  1. 액터 컨텍스트로 전환합니다.
  2. 액터가 독점 권한을 해제할 때까지 기다립니다.
actor Library {
    // 격리된 프로퍼티; 읽기 위해서는 `await`가 필요합니다.
    var books: [String] = []

    // 액터 메서드 (외부에서 호출될 때는 암시적으로 async).
    func addBook(_ title: String) {
        books.append(title)
    }

    func getBookList() -> [String] {
        books
    }

    // `nonisolated` 메서드: `await` 없이 호출 가능.
    nonisolated func libraryName() -> String {
        "A library of books"
    }
}

사용 예시:

let library = Library()

// ❌ 액터 메서드를 동기적으로 호출할 수 없습니다.
library.addBook("hola")   // 컴파일 오류

Task {
    await library.addBook("Dopamine Nation")
    let books = await library.getBookList()
    print(books)               // ["Dopamine Nation"]

    // 프로퍼티 직접 읽기 (await 필요).
    await library.books.forEach { print($0) }

    // ❌ 액터 외부에서 프로퍼티를 변형할 수 없습니다.
    // library.books.append("Another")   // 오류
}

@MainActor 같은 global actor와 일반 액터는 어떻게 다르나요?

  • 일반 액터: 각 인스턴스마다 고유한 격리 도메인을 가집니다.
  • 글로벌 액터: 해당 액터로 표시된 모든 인스턴스가 같은 도메인을 공유합니다 (예: @MainActor). 여러 부분이 동일한 동시성 제한 하에서 동작해야 할 때 유용합니다.

Sendable 프로토콜에 따라 공개 API가 스레드‑안전하다고 판단되려면 어떤 조건을 만족해야 하나요?

인터페이스가 격리 도메인 간에 안전하려면:

  • 공개적으로 가변 수정자를 노출하지 않아야 합니다.
  • 내부적으로 자체 잠금 메커니즘을 구현해야 합니다 (예: NSLock, DispatchQueue).
  • 수정자는 copy‑on‑write 방식을 사용해야 합니다 (값 타입과 유사).

표준 라이브러리의 많은 타입이 이미 Sendable을 채택하고 있습니다. 컴파일러는 모든 멤버가 Sendable인 경우 암시적으로 준수를 추론할 수도 있습니다:

// ✅ 모든 멤버가 Sendable이므로 암시적 준수

멤버는 Sendable입니다.

struct SomeStruct {
    var someIntValue: Int
}
// ❌ 암시적으로 준수하지 않음; 클래스는 레퍼런스 타입입니다.
class SomeClass {
    var someIntValue: Int = 0
}

낭송

  • Int 프로퍼티를 가진 struct는 암시적으로 Sendable을 준수하지만, 같은 프로퍼티를 가진 class는 그렇지 않을까요?
    struct는 값 타입이기 때문에 복사할 때 새로운 독립 인스턴스가 생성되어 데이터 레이스를 방지합니다. 반면 class는 참조 타입이며 여러 도메인에서 동시에 변형될 수 있습니다.

  • 값이 두 격리 도메인 사이를 이동할 때 무슨 일이 일어나는지 직접 설명해 주실 수 있나요?
    Swift는 값이 Sendable인지 확인합니다. Sendable이면 컴파일러가 이동을 허용하고, 동일한 데이터에 대한 비동기 동시 접근이 없음을 보장합니다.

  • 언제 …가 의미가 있을까요? (필요한 상황에 맞게 계속 작성하세요).

액터 내부에서 메서드를 nonisolated 로 표시하는 방법

액터의 상태를 보호할 필요가 없을 경우 nonisolated 로 표시할 수 있습니다. 예를 들어 메서드가 스칼라 값이나 상수 값을 반환할 때 이런 경우가 해당됩니다.

검토

1. 공개 API가 동시성 도메인 간에 안전하게 사용될 수 있는 세 가지 조건은 무엇인가요?

  1. 불변성 – 노출된 값은 생성된 이후에 수정될 수 없습니다.
  2. Sendable – 관련된 모든 타입이 Sendable 프로토콜을 준수합니다.
  3. 부수 효과 없음 – API가 외부 상태에 접근하거나 수정하지 않아 스레드 간에 공유될 수 있는 상태를 변경하지 않습니다.

2. Swift 6.2에서 Sendable의 기본 동작은 어떻게 바뀌었나요?

Swift 6.2는 **nonisolated(nonsending)**을 도입하여, 함수와 클로저가 격리 경계를 넘지 않는 한 Sendable이 되지 않도록 합니다. 따라서 컴파일러가 nonisolated 컨텍스트에서 자동으로 Sendable 준수를 강제하지 않아, 전송이 필요 없는 코드와의 상호 운용성이 향상됩니다.

참고 문헌

  • Van der Lee, A. (2025). Swift Concurrency Course [온라인 코스]. avanderlee.com.
0 조회
Back to Blog

관련 글

더 보기 »

2026년 SwiftUI: 모든 것을 바꾼 7가지 기능

SwiftUI는 이제 더 이상 “프로토타입 전용”이 아니다. SwiftUI가 2019년에 출시되었을 때, 회의론자들은 이것이 프로덕션에 적합하지 않다고 말했습니다. 2026년에는, 이것이 기본 선택이 되었습니다…

모던 JS 토크 async function

개요 비동기 함수는 Async Function 객체를 반환합니다. async와 await 키워드를 사용하면 비동기 처리를 보다 간결하게 작성할 수 있습니다.