Swift Concurrency 10 편 - nonisolated, Sendable

김재형·2024년 7월 6일
1
post-thumbnail
post-custom-banner

들어가기에 앞서

Swift Concurrency 1편 에서 이어 지는 내용 입니다.
1편부터 보고 와주시길 바랍니다.

nonisolated

nonisolated는 특정 함수나 속성이 어떤 actor에 의해 격리되지 않는다는 것을 나타냅니다.
actor는 상태를 보호하기 위해 동시성을 관리하나, 특정 경우에 따라 코드가 actor의 격리 규칙에서 벗어나야 할 상황이 생길수 있습니다.
즉 -> solated한 데이터를 nonisolated 하게 만들어주는 키워드 입니다.

actor MyActor {
    private var count: Int = 0
	let myName: String = "김재형"
    func increment() {
        self.count += 1
    }

    func getCount() -> Int {
        return self.count
    }

    // `isolated` 키워드를 사용한 메서드
    func resetCount(isolatedTo actor: isolated MyActor) {
        actor.count = 0
    }

    // `nonisolated` 키워드를 사용한 메서드 (예시)
    nonisolated func whatAmIName() -> String {
        return myName
    }
    
    /*
    nonisolated 키워드를 사용한 메서드는 actor의 상태에 접근하지 않거나,
    안전하게 접근할 수 있는 경우에 사용됩니다.
    */
}

Sendable

Actor는 Sendable 프로토콜을 채택하고 있습니다.
문서에 따르면 해당 프로토콜은 객체가 다른 스레드나 actor로 안전하게 전송될 수 있음을 보장한다고 되어 있습니다.
actor, let으로 선언된 property, Value type등은 Sendable 합니다.

Sendable을 준수하는 객체는 다른 스레드나 actor로 안전하게 전송 할 수 있죠.
그렇다면 아래와 같은 경우는 어떨까요?

class Who {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}


struct human {
    let who: Who
}

human 구조체는 값 타입(value type)이지만, Who 객체를 프로퍼티로
가지고 있을때는 말이죠.

// error: Type 'human' does not conform to protocol 'Sendable'
extension human: Sendable {}

해당 하는 것과 같이 Sendable 하지 않기 때문에 에러가 발생하게 됩니다.

Sendable 특징

자 에러가 왜 발생하는지 다시 특징을 정리해서 살펴 봅시다.

  • Sendable을 준수하는 객체는 여러 스레드에서 동시에 접근하더라도
    데이터 경쟁이나 상태 불일치가 발생하지 않음을 보장합니다.

즉. 데이터 경쟁(data race)과 상태 불일치 문제를 방지하기 위함 인데.
클래스는 참조 타입(reference type) 임으로,
즉 여러 스레드나 actor가 동일한 인스턴스를 공유할 수 있음으로...! 문제가 발생 하는거죠.

어떻게 해결하는가?

1. Actor

Actor는 Sendable을채 택하고 있습니다. 즉 Actor 로 변경하여
해당 문제를 해결 할수 있죠.

actor Who {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func updateName(newName: String) {
        self.name = newName
    }
    
    func getName() -> String {
        return self.name
    }
}

struct Human: Sendable {
    let who: Who
}

2. Final + Senable

혹은 해당 클래스를 Sendable 프로토콜을 채택하고, Final 키워드를 통해
static Dispatch 하게 하여 문제를 해결할수 있겠네요!
Final키워드를 통해 동시성 환경에서 예측 가능한 동작을 보장하는 데 도움이 됩니다.

final class Who: Sendable {
    let name: String // var 은 문제 발생
    
    init(name: String) {
        self.name = name
    }
}

마무리 하며

다음 편은 dataRace를 방지에 관하여 다루어 보도록 하겠습니다.
오늘도 모두 고생 많으셨습니당!

profile
IOS 개발자 새싹이
post-custom-banner

0개의 댓글