일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 동시성
- struct
- CS
- 네트워크
- 기초문법
- swift
- MVVM
- uikit
- 옵셔널
- Kingfisher
- collectionview
- 구름톤 유니브
- 스트럭트
- WeatherKit
- mvc
- 실습
- 앱개발
- SwiftUI
- async
- 세종대학교
- GCD
- ios
- 프로토콜
- 이론
- Optional
- 토이프로젝트
- 반응형
- 대표
- RxSwift
- 학과별커뮤니티
- Today
- Total
스윞한 개발자
Actor 톺아보기 👀 본문
안녕하세요. 동시성 프로그래밍과 관련해 지난 포스팅에서 GCD, swift Concurrency에 대해 정리해 보았습니다. GCD 내부 코드에서 경쟁 상태를 방지하기 위해 lock, queue 등을 사용해줘야 했는데! 이제는 actor를 통해 대응이 가능해졌습니다.
이번 포스팅에서는 Actor에 대해 톺아보겠습니다!

먼저, 기존의 lock 등을 사용해 경쟁 상태를 관리할 수 있었는데 Actor가 등장하게 된 배경에 대해 간략히 정리해 보겠습니다.
NSLock을 사용할 경우에 모든 경우에 개발자가 직접 관리해야 하기 때문에 휴먼 에러가 발생할 가능성이 있습니다. 해제를 깜빡하거나 잘못된 순서로 사용하면 데드락이 발생할 수 있습니다.
아래와 같이 비교해 볼 수 있습니다.
수동으로 lock을 관리해야 함 | actor가 자동으로 동기화 |
교착 상태(Deadlock) 발생 가능 | 데드락 방지 |
여러 스레드에서 접근 시 동시성 문제 발생 가능 | actor 내부 상태는 자동 직렬화 |
lock을 잘못 사용하면 성능 저하 | async/await을 활용한 효율적 동시성 관리 |
DispatchQueue.sync 사용 시 스레드 블로킹 발생 | async 기반으로 블로킹 없는 실행 |

https://developer.apple.com/documentation/swift/actor
Actor | Apple Developer Documentation
Common protocol to which all actors conform.
developer.apple.com
# Actor 란?
Actor는 스위프트 동시성 프로그래밍에서 경쟁 상태를 방지하도록 설계되었습니다. 이 경쟁상태에서 Actor를 사용하게 된다면, 여러 스레드에서 공유자원에 대해 접근을 시도할 때 안전하게 데이터를 공유할 수 있습니다.
여러 스레드가 동시에 하나의 Actor에 접근이 가능하지만, Actor은 내부 상태변경 작업은 1회당 하나의 작업만이 수행되게 됩니다. 그렇기 때문에 데이터 경쟁상태를 방지할 수 있게 해줍니다.
Actor는 인스턴스 데이터를 프로그램의 나머지 부분에서 격리(isolate)합니다. 즉, Actor에 대한 접근은 직렬화됩니다.
결국, Actor의 역할은
1. 여러 작업에 대해 공유자원을 관리하는 역할
2. 여러 스레드에서 접근하는 공유자원에 대해 격리(isolate)시키고, 이 공유자원에 대해서 직렬화하게 접근하도록 처리하는 역할
3. 내부의 공유 가능한 프로퍼티는 외부에서 mutate(값을 변경하는(수정하는) 함수나 메서드) 할 수 없으며, 내부에서만 가능
4. 공유자원을 격리시키지 않을 경우에 nonisolated 키워드를 붙여 격리 대상에서 제외 가능
이 처럼 데이터의 경쟁상태가 발생할 수 있는 객체를 Actor로 감싸게 되면 안전하게 관리가 가능합니다. 하지만, 적절할 때 사용하는 것이 중요합니다. 잘못 사용하게 될 경우 반대로 동시성 문제가 발생할 수도 있습니다.
Actor는 직렬화된 접근 방식을 사용하기 때문에, 상태 변경과 관련된 주요 로직만 처리하도록 하는 것이 좋습니다.
import Foundation
actor StorageManager {
var storage: [String] = []
func save(_ value: String) async -> [String] {
await preProcess(value)
storage.append(value)
return storage
}
func preProcess(_ value: String) async {
try? await Task.sleep(nanoseconds: 1_000_000_000)
print("\(value) 전처리 완료")
}
}
final class Tester {
let storage = StorageManager()
func test() {
asyncSaveAndPrint(data: "a")
asyncSaveAndPrint(data: "b")
asyncSaveAndPrint(data: "c")
asyncSaveAndPrint(data: "d")
asyncSaveAndPrint(data: "e")
}
func asyncSaveAndPrint(data: String) {
Task {
let result = await storage.save(data)
print(result)
}
}
}
let tester = Tester()
tester.test()
actor의 함수는 동시 실행을 보장하지 않습니다. StorageManager는 Actor이므로 동시에 여러 개의 save호출이 들어와도 한 번에 하나씩 직렬화 처리가 됩니다. save의 호출은 전처리가 끝난 후 배열에 추가됩니다. save가 완료될 때마다 현재까지 저장된 모든 값을 출력합니다. 그렇기 때문에 Actor도 적절한 경우에 사용해 주어야 합니다.
nonisolated private func preProcess(_ value: String) async {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1초 대기
print("\(value) 전처리 완료")
}
이 처럼 전처리 과정을 격리에서 벗어나 실행하게 되면 문제를 해결할 수 있습니다.
#GlobalActor란?
Actor는 하나의 인스턴스에 대해서 격리 영역을 만듭니다. GlobalActor는 하나의 인스턴스에 국한되지 않고, global 한 영역으로 격리의 범위를 확장시킨 개념입니다.
Actor 안에서 nonisolated를 통해 격리되지 않게 지정할 수 있었습니다. 이와 반대되는 메커니즘으로, Actor 밖에서 격리시키고 싶을 때 Global Actor를 정의해 사용할 수 있습니다.
https://developer.apple.com/documentation/swift/globalactor
GlobalActor | Apple Developer Documentation
A type that represents a globally-unique actor that can be used to isolate various declarations anywhere in the program.
developer.apple.com
@globalActor
actor MyGlobalActor {
static let shared = MyGlobalActor()
}
@MyGlobalActor
func someFunction() {
// MyGlobalActor에서만 실행
}
위와 같이 전역적으로 접근 가능한 액터를 지정할 수 있습니다. 아래의 함수에서는 @MyGlobalActor 어트리뷰트를 사용하여 해당 액터에 접근하게 됩니다. global actor로 사용될 구조체, 클래스 앞에 키워드를 붙여줍니다. 많이 사용되는 예시 중 하나는 MainActor가 있습니다.
## MainActor
UI와 관련된 모든 작업은 사용자가 상호작용하는 Main Thread에서 진행되어야 합니다. 동시성을 관리할 때, Actor를 생성하면 일반적으로 해당 코드가 백그라운드 스레드에서 실행되도록 지정합니다. 그래서 메인에서 실행되어야 할 코드를 MainActor에 격리해야 합니다. 이를 위해 주로 사용되는 것이 @MainActor Attributes입니다.
이번 포스팅에서는 동시성 프로그래밍에서 경쟁상태를 관리하기 위한 방법으로 Actor에 대해 공부하고 정리해 보았습니다. 다음 포스팅에서는 더 유익한 내용으로 돌아오겠습니다. 감사합니다.

'Swift 이론' 카테고리의 다른 글
DiffableDatasource의 이해 (0) | 2025.02.16 |
---|---|
iOS - ARC(Swift 메모리 관리 기법) (2) | 2025.02.09 |
이미지 리사이징 vs 이미지 다운 샘플링 (0) | 2025.02.03 |
Swift Concurrency(with GCD) (0) | 2025.01.23 |
뷰 드로잉 사이클 - View Drawing Cycle (0) | 2025.01.20 |