---
# System prepended metadata

title: Actor 정리

---

# Actor 정리

[Actor 개념 정리]
- 동시성 코드간에 정보를 안전하게 공유할 수 있게 해주는 것
ㄴ 한 번에 하나의 작업만 변경 가능한 상태에 접근할 수 있도록 허용함
ㄴ 그렇기 때문에 Actor 내부에 있는 `변수(var)`에 접근하는 경우, `await`을 붙여줘야 함. 안 붙여주면 에러남
ㄴ 값이 변경될 일 없는 `상수(let)`는 `await` 안 붙여줘도 됨

- Actor 내부 프로퍼티는 다 actor-isolatied 프로퍼티 
ㄴ Swift 는 Actor 내부의 코드만 Actor에 접근(write)할 수 있도록 보장함
ㄴ 이 보장을 actor isolation 이라고 함
ㄴ 그렇기 때문에 외부에서 Actor의 내부에 있는 프로퍼티 값을 변경하는 경우, 에러가 남
ㄴ 만약 Actor 내부에 있는 프로퍼티가 클래스 타입이라면, 클래스 타입안에 있는 프로퍼티 값 변경에 대해서는 actor isolation이 아님

- actor는 다른 스레드가 쓰기를 하는 동안 한 스레드가 변경 가능한 객체에 액세스할 때 발생할 때 생기는 문제를 해결해줄 수 있음

[발표 중 나온 의문들]
- `isolated`이 무엇인가?
- `actor` 가 다른 독립된 스레드에서 실행되는가? 
- `actor` 내부가 어떤 스레드에서 실행되는가?
- `actor`가 어떤 원리로 돌아가고 `await async` 랑 어떤 연관이 있는가?
- `Race Condition` 과 `Data Race`이 무엇이고, `actor`는 어떤 것과 더 관련이 있는가
- `actor`는 데이터 레이스에 초점을 맞춰하는가? 
- 데이터 레이스에 초점을 맞춘다는 것이 디스패치 큐하고 비교하면서 한다는 것인가?

[참고 사이트]
- https://zeddios.tistory.com/1303
- https://zeddios.tistory.com/1304
- https://developer.apple.com/videos/play/wwdc2021/10133
- https://swiftsenpai.com/swift/actor-prevent-data-race/
- https://www.avanderlee.com/swift/race-condition-vs-data-race/

[예시 코드]
- 회의 시간에 테스트 해본 코드
```swift
actor SomeActor {
    let str: String
    var numbers: [Int]
    private(set) var number: Int
    
    // SomeClass 타입
    let someClass1 = SomeClass(a: 0)
    var someClass2 = SomeClass(a: 1)
    
    // Int 타입
    let someA1 = SomeClass(a: 2).a
    var someA2 = SomeClass(a: 3).a
    
    // SomeStruct 타입
    let someStruct1 = SomeStruct(b: 4)
    var someStruct2 = SomeStruct(b: 5)
    
    // Int 타입
    let someB1 = SomeStruct(b: 6).b
    var someB2 = SomeStruct(b: 7).b
    
    init(str: String, number: Int) {
        self.str = str
        self.numbers = [number]
        self.number = number
    }
    
    func change(number: Int) {
        self.number = number
    }
}

class SomeClass {
    var a: Int
    
    init(a: Int ) {
        self.a = a
    }
}

struct SomeStruct {
    var b: Int
    
    init(b: Int ) {
        self.b = b
    }
}

let someActor = SomeActor(str: "하이엑터", number: 1228)
        
// let은 await 안 붙여줘도 됨
print(someActor.str)

// var는 await 붙여줘야 함
// print(someActor.numbers) // Error
// print(someActor.number) // Error
print(await someActor.numbers)
print(await someActor.number)

// actor 내부에 참조타입 프로퍼티가 있으면, 참조타입의 값에 대해서는 변경 가능
// 참조타입의 값(a,b)이 변해도 actor 내부에 있는 프로퍼티(someClass1, someClass2)가 갖고 있는 주소값에 대해서는 변화가 없으므로 참조타입 내부 프로퍼티 값은 변경가능
someActor.someClass1.a = -1
print(someActor.someClass1.a)

await someActor.someClass2.a = -2
print(await someActor.someClass2.a)

// Struct는 값 타입이므로 let이면 변경 불가
// someActor.someStruct1.b = -3 // Error

// var여도 actor 내부 프로퍼티는 isolated property 이므로 직접 변경 불가
// someActor.someStruct2.b = -3 // Error


// actor 내부 프로퍼티를 변경하려면 내부 로직에 의해만 가능함
await someActor.change(number: 100)
```

- Language guide에 소개된 코드
```swift
actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int
    
    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}

let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
print(logger.max)
```

- wwdc에 소개 된 코드
```swift
actor Counter {
    var value = 0

    func increment() -> Int {
        value = value + 1
        return value
    }
}

let counter = Counter()
Task.detached {
    print(await counter.increment()) // 1, 2
}

Task.detached {
    print(await counter.increment()) // 2, 1
}
```
