Global Actor란 프로젝트 내부에서 접근 가능한 유일한 actor로 어디서든 다양한 선언을 isolate하는데 사용할 수 있는 타입입니다

 

 

Global Actor 이전에 Actor란

아래는 메서드로 간단한 데이터를 가져오도록 하는 코드입니다. 이런 상황에서는 문제가 발생하지 않습니다.

func getData() async {
    let data = await manager.getDataFromDatabase() // actor이므로 자동 async 코드로 인식
    self.dataArray = data
}

 

하지만 엄청 무거운 작업을 Main Thread 에서 작업한다면 문제가 발생할 수 있습니다. 이런 목적으로 Actor이 만들어졌습니다.

Global Actor 사용 목적

만약 아래와 같은 actor가 존재한다고 하였을 때 아래 actor 말고 외부에서 아래의 actor에 isolated 된 메서드로 만들고 싶으면 MyNewDataManager actor를 Global 하게 사용하면 해결이 될 것입니다. 이것이 바로 Global Actor를 사용하는 목적입니다.

Global Actor를 이용하면 Global하게 프로젝트 어디서든 Actor를 Global하게 싱글톤으로 사용 가능
actor MyNewDataManager {
    
    func getDataFromDatabase() -> [String] {
        return ["One", "Two", "Three"]
    }
}

 

 

Global Actor 파악하기

  • iOS 13.0 버전부터 사용할 수 있습니다.
  • 기존에 선언된 actor를 shared 인스턴스로 만들어 접근하도록 합니다.
  • 싱글톤으로 사용되어야 합니다.

 

Global Actor 선언

@globalActor로 선언된 코드는 반드시 shared 인스턴스를 만들어야합니다.

@globalActor struct MyGlobalActor {
    static var shared = MyNewDataManager()
}

 

이렇게 MyNewDataManger actor를 가지고 @globalActor를 만들었다면 이제 actor 에 존재하는 메서드들은 @globalActor의 shared 싱글톤을 통해 사용합니다.

class GlobalActorViewModel: ObservableObject {
    
    @Published var dataArray: [String] = []
    let manager = MyGlobalActor.shared
    
    @MyGlobalActor
    func getData() async {
        let data = await manager.getDataFromDatabase()
        self.dataArray = data
    }
}

 

추가로 getData 메서드에 @MyGlobalActor를 사용하였는데 이것은 globalActor인 MyGlobalActor에 isolated 되는 메서드로 지정하는 것입니다.

globalActor를 이용하여 actor 외부에서 actorisolated 시키는게 가능해졌습니다.
@MyGlobalActor
func getData() async {

 

 

MainActor

MainActor는 GlobalActor 종류 중 하나인데 Actor와 다르게 Main Thread에서 작업을 수행한다고 지정하는 것 입니다.

보통은 Main Thread는 UI를 업데이트하는데 사용되는 스레드입니다. 즉 UI에 관여하는 데이터에 @MainActor를 붙여주면 해당 데이터를 가지고 작업을 할 때 Main Thread에서 작업이 이루어진다고 지정할 수 있습니다.

 

다음은 UI의 값이 반영되는 데이터입니다, UI에 해당 데이터가 직접적으로 관여하므로 Main Thread에서 작업이 이루어져야 합니다. 그러므로 @MainActor를 사용합니다.

@MainActor @Published var dataArray: [String] = []

 

추가로 해당 데이터에 값을 수정하기 위해서는 @MainActor 프로퍼티 래퍼를 사용하기 때문에 MainActor.run 메서드를 이용하여 작업할 내용을 클로저 내부에 넣어줍니다.

class GlobalActorViewModel: ObservableObject {
    
    @MainActor @Published var dataArray: [String] = []
    let manager = MyGlobalActor.shared
    
    @MyGlobalActor
    func getData() async {
        let data = await manager.getDataFromDatabase()
        await MainActor.run(body: {
             self.dataArray = data
        })
    }
}

 

추가로 클래스 자체를 MainActor로 지정할 수 있다는 특징도 있습니다.

@MainActor class GlobalActorViewModel: ObservableObject {

 

 

ytw_developer