# 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
}
```