[swiftUI] Actor, isolated, nonisolated 에 대해

Jenny·2024년 3월 5일

Actor

  • actor는 한번에 하나의 작업만 데이터에 접근 할 수 있도록 내부 변경 가능 상태에 대한 비동기 접근을 제어하는 참조 타입이다.
  • actor는 속성, 생성자, 메서드를 포함한다는 점에서 클래스와 매우 유사하다.
  • actorclass의 큰 차이점을 가지고 있다 그것은 비동기 함수 또는 Task 클로저 내와 같은 비동기 콘텍스트 내에서만 생성 및 액세스 할 수 있다는 것이다. 또한 actor 메서드를 호출 하거나 속성에 접근 할 때 await 키워드를 반드시 사용해야 한다.
  • actor인스턴스에 포함된 데이터는 앱의 다른 코드와 격리된다. 이러한 격리 는 인스턴스 데이터를 변경 하는 메서드가 호출될 때, 다른 곳의 코드에서 해당 메서드를 호출 할 수 있게 되기 전에 메서드가 완전히 실행 되는 것을 보장한다.
  • actor 는 클래스와 다르게 상속을 지원해주지 않는다. 다만 프로토콜을 지원해준다. 수평 확장을 지원해줌

정리하자면 data race(데이터 경쟁)을 피하기 위해 Actor를 사용하는 것이며 Actor는 Shared Mutable State에 대한 동기화 메커니즘이다. 때문에 상태(데이터)에 동시에 접근하지 않도록 해준다.

actor BuildErrorMessage {
    
    var message: String
    let statusCode: Int
    
    init(message: String, statusCode: Int) {
        self.message = message
        self.statusCode = statusCode
    }
    
    func setErorr(message: String) {
        self.message = message
    }
    
    nonisolated func setStatusCode() -> Int {
        return statusCode
    }
    
}

isolated

  • actor는 각자의 data를 격리(isolated)라는 개념을 이용해 보호합니다. 이를 통해 한 데이터(자원)에 동시에 단 하나의 스레드만 접근할 수 있도록 해 의도치 않는 data race 를 막을 수 있습니다.
  • 만약 data가 immutable stateactor를 사용할 필요가 없다. 하지만 모든 데이터가 immutable한 특성을 가지고 있지 않기 때문에 actor를 사용하여 data race 를 방지하는 것이다.
  • actor 내에 정의된 stored, computed instance properties, instance methods, instance subscripts는 모두 기본적으로 actor-isolated 상태 이다.
  • actor-isolated 상태인 것은 actor 내에서만 접근 할 수 있다. 즉 self를 통해서 접근이 가능하다. 다만 immutable 의 상태를 가진 let은 self 키워드를 명시하지 않고 접근이 가능하다. 이것을 Cross-Actor Reference 라고 한다.

nonisolated

  • actor 내부에서 data를 비격리(nonisolated)상태로 만들기 위해서는 nonisolated 키워드를 명시하면 된다.
  • nonisolated 함수에서 만약 actor 내부에 immutable state 에 접근한다면 굳이 await 키워드를 사용하지 않아도 된다. isolated 일 경우 await 키워드를 사용해야 한다.
class BuildMessage {
    var message: String
    let greeting: String
    
    func setName(name: String) {
        self.message = "\(greeting) \(name)"
    }
    
    init(message: String, greeting: String) {
        self.message = message
        self.greeting = greeting
    }
}



actor BankAccount {
    let accountNumber: Int
    var balance: Double
    let accountName: String
    nonisolated var displayName: String {
        return self.accountName + "입니다."
    }
    
    init(accountNumber: Int, balance: Double, accountName: String) {
        self.accountNumber = accountNumber
        self.balance = balance
        self.accountName = accountName
    }
}

extension BankAccount {
    enum BankError: Error {
        case insufficientFunds
    }
    
    func transform(amount: Double, to other: BankAccount) throws {
        if amount > self.balance {
            throw BankError.insufficientFunds
        }
        
        print("Transferring \(amount) from \(accountNumber) to \(other.accountNumber)")
        self.balance = balance - amount
        
        print(other.accountNumber)
/*        other.balance = other.balance + amount*/ // Actor-isolated property 'balance' can not be mutated on a non-isolated actor instance
    }
    
    nonisolated func getAccountNumber() -> Int {
        return accountNumber
    }
    
profile
"Jenny 있게 iOS 개발을 하며 대체 불가능한 인재가 되자"

0개의 댓글