개념

특정 작업이 전역적으로 단일 스레드에서 실행되도록 보장하는 장치

  • 우리는 @MainActor라는 키워드만 추가하게 되면 main thread에서 동작한다는 것을 보장할 수 있다.
  • 어떻게 가능한 것일까?

MainActor

@globalActor 
final public actor MainActor: GlobalActor {  
  
	public static let shared: MainActor  
    
	@inlinable nonisolated final public var unownedExecutor: UnownedSerialExecutor { get }  
  
	@inlinable public static var sharedUnownedExecutor: UnownedSerialExecutor { get }  
  
	@inlinable nonisolated final public func enqueue(_ job: UnownedJob)  
  
	public typealias ActorType = MainActor  
}
 
  • MainActor는 GlobalActor를 채택하고 있음을 확인할 수 있다.
  • 해당 actor는 자신의 고유한 실행흐름을 가지고 있으며, 전역적으로 해당 실행흐름을 특정 함수나 프로퍼티에 선언하여 처리가 가능하다.

Customization

@globalActor actor UserProfileActor {  
	static var shared = UserProfileActor()  
}
  • 그렇다면 고유의 실행흐름을 가지는 Actor 역시 만들 수 있을 것이다.

Usage

@MainActor  
final class UserViewModel {  
	func updateProfilePhoto() {  
		print("Update the profile photo done on MainThread: \(Thread.isMainThread)")  
		print("Update the profile photo done on Thread: \(Thread.current)")  
	}  
  
	@UserProfileActor  
	func fetchProfilePhoto() async {  
		print("Fetch the profile photo done on MainThread: \(Thread.isMainThread)")  
		print("Fetch the profile photo done on Thread: \(Thread.current)")  
		await updateProfilePhoto()  
	}  
}
Fetch the profile photo done on MainThread: false  
Fetch the profile photo done on Thread: <NSThread: 0x600000c34940>{number = 7, name = (null)}  
  
Update the profile photo done on MainThread: true  
Update the profile photo done on Thread: <_NSMainThread: 0x600000c280c0>{number = 1, name = main}
  • 두 개 이상의 Annotation을 설정하고 실행했을 때의 결과이다.
  • 함수에 설정하는 것에따라 실행흐름이 바뀌는 것을 확인할 수 잇다.

Reference