티스토리 뷰

반응형

 

안녕하세요. 개발자 멍구입니다! 

iOS 개발을 하다 보면 "동시성", "데이터 경쟁(data race)", "스레드 안전성" 같은 말들이 자주 들리죠? 처음 들으면 어렵게 느껴질 수 있지만, 오늘은 그런 개념들을 단번에 정리해주는 핵심 키워드 두 가지를 소개해드릴게요.

바로 ActorSendable입니다. 앱이 복잡해지고, 멀티태스킹이 많아질수록 중요해지는 이 개념들, 오늘 알아보겠습니다.

 


Actor? 데이터 경합 문제를 깔끔하게 해결하는 방법

먼저 Actor부터 볼게요.

"Actor는 일종의 안전한 방입니다." 여러 사람이 동시에 들어와서 방 안의 물건을 엉망으로 만들지 않도록, 한 명씩만 차례대로 들어와서 방 안의 상태를 변경할 수 있도록 해요.


Swift에서 actor는 class처럼 참조 타입이지만, 단 하나의 큰 차이가 있어요. 동시에 여러 스레드에서 접근하더라도 데이터 충돌이 일어나지 않게 보호해주는 장치라는 점이죠. 그 외에도 아래와 같은 특징이 있습니다.

  • 내부 상태에 대한 접근을 순차적으로 처리합니다. (상태에 대한 동시 접근을 방지)
  • 덕분에 data race 문제를 자연스럽게 피할 수 있어요.
  • ❌ 단, class와 달리 상속이 안 되기 때문에 override, final 같은 키워드는 사용할 수 없어요.

한 마디로, Actor는 멀티태스킹 환경에서 우리의 앱이 안전하게 작동하도록 도와주는 수호자라고 볼 수 있겠네요.

💡 참고: Actor는 내부적으로 Sendable 프로토콜을 암시적으로 따릅니다. (즉, 특별히 선언하지 않아도 Sendable로 간주돼요.)



 


Sendable? 여러 스레드에서 안전하게 전달 가능한 타입

Swift는 구조체(struct)나 열거형(enum)처럼 값 타입을 기본으로 사용하죠. 그런데 동시성 환경에서는 이 값들이 여러 스레드에서 동시에 변경되면 문제가 생길 수 있어요.

그래서 Swift 5.5부터 등장한 게 바로 Sendable입니다.

"Sendable은 어떤 값이 여러 작업(Task) 간에 안전하게 전달될 수 있는지를 나타내는 약속"

Swift 컴파일러는 Sendable을 따르는 타입이라면 여러 스레드 사이에서 마음 놓고 전달해도 괜찮다고 판단하고, 이를 컴파일 타임에 확인해줍니다. 스레딩 문제를 조기에 확인하고, 처리할 수 있도록 해주죠.

 


Sendable Class 만들 때 주의할 점

기본적으로 Sendable한 구조체, 열거형 등의 값 타입에 비해 클래스를 Sendable하게 만들려면 몇 가지 조건을 지켜야 해요.

  1. final 키워드가 필요해요 (상속을 막기 위해)
  2. 변경되지 않는(immutable) 속성만 포함해야 해요
  3. NSObject 등 Objective-C 기반의 슈퍼 클래스는 사용하면 안됨.

예외적으로, @MainActor로 선언된 클래스는 자동으로 Sendable이 됩니다. 왜냐면 메인 액터가 상태 접근을 하나씩 조절하기 때문이죠.

하지만 이 조건을 만족하지 않는 클래스를 Sendable로 만들고 싶다면?

@unchecked Sendable

을 붙여줄 수 있어요. 이건 말 그대로 “컴파일러야, 내가 책임질 테니 그냥 통과시켜줘!”라는 뜻이에요. 그만큼 신중하게 사용해야 합니다. 😅

이걸 사용하면 개발자가 수동으로 Sendable할 수 있도록 처리해주어야하니 주의해야해요.

 


Sendable Functions & Closures: 안전하게 값 전달하는 법

함수나 클로저에서도 @Sendable 속성을 사용할 수 있어요.

let sendableClosure = { @Sendable (number: Int) -> String in
    return number % 2 == 0 ? "Even" : "Odd"
}

이렇게 정의된 클로저는 내부에서 캡쳐하는 값도 모두 Sendable 타입이어야 해요.

그 외로 Task.detached와 같은 비동기 문맥에서는 Swift가 자동으로 "이건 Sendable 클로저겠지?" 하고 판단해요.

💡Sendable 클로저를 만들 땐 값을 복사해서 쓰고, 값도 안전한 타입이어야 해요!




Sendable Tuples & Metatypes 에서의 Sendable

튜플은 그 내부 요소들이 Sendable이면 전체적으로 Sendable로 간주됩니다. 타입 메타타입 (Int.TypeString.Type)도 암시적으로 Sendable 합니다.

  • (Int, String) → 둘 다 Sendable
  • (Int, UIView) → UIView는 Sendable 하지 않으므로, 해당 튜플은 Sendable 하지 않음. ❌

 


마무리 정리: actor와 Sendable 개념, 왜 알아야 할까?

앱이 커질수록 비동기 작업은 피할 수 없고, 비동기 작업이 많아질수록 안전하게 데이터 관리하는 것이 중요해요.


Swift의 Actor, Sendable, @Sendable, @MainActor는 이런 상황에서 에러 없이, 예측 가능한 앱을 만들도록 도와주는 도구예요.특히 요즘 같이 async/await 패턴이 기본이 된 Swift 세계에서는 Sendable과 Actor는 "선택"이 아닌 "필수"라고 할 수 있어요.

앱 규모가 커질 수록 훨씬 복잡하고 많은 스레드 비동기 작업이 필요하고, 그럴수록 data race condition을 주의해야합니다. 따라서actor, Sendable 등의 Swift Concurrency 사용 간의 개념들에 대해 잘 알고 활용해야겠습니다.

지금까지 iOS Data race 해결에 사용되는 개념, 도구인 Actor와 Sendable 적용 케이스 등에 대해서 알아봤어요. 많은 피드백 부탁드려요. 감사합니다!

 

Reference

 

Sendable | Apple Developer Documentation

A thread-safe type whose values can be shared across arbitrary concurrent contexts without introducing a risk of data races.

developer.apple.com

 

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
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 31
글 보관함