Why This Work Exists
Actor를 실제 타입처럼 쓰다 보면 곧 프로토콜 채택과 utility 함수 작성 문제가 나온다. 이 문서는 “왜 Hashable이 막히는가”, “왜 `isolated` 파라미터를 쓰는가”를 한 번에 정리하기 위한 3편이다.
ZeddiOS의 Swift ) Actor (3) 글을 바탕으로, actor가 프로토콜을 채택할 때 생기는 제약과 `isolated` 파라미터를 이용해 actor 파라미터의 상태를 함수/프로퍼티 본문에서 직접 다루는 방법을 정리한다.
2026-04-09
Actor를 실제 타입처럼 쓰다 보면 곧 프로토콜 채택과 utility 함수 작성 문제가 나온다. 이 문서는 “왜 Hashable이 막히는가”, “왜 `isolated` 파라미터를 쓰는가”를 한 번에 정리하기 위한 3편이다.
흔한 오해는 actor 내부에 메서드를 정의했으니 프로토콜 요구사항도 다 자동으로 만족할 수 있다는 생각이다. 하지만 protocol requirement의 호출 방식과 actor isolation 규칙이 충돌하는 경우가 있다.
더 정확한 표현은 이렇다. 일반 actor 메서드는 actor-isolated여도 괜찮지만, protocol requirement가 nonisolated 형태를 기대하면 그대로는 채택할 수 없다.
`actor 안에 정의했다`가 중요한 게 아니라, `그 메서드가 어떤 호출 계약을 만족해야 하느냐`가 중요하다.
`deposit()` 같은 메서드는 그냥 actor의 일반 인스턴스 메서드다. 따라서 actor isolation 규칙 안에서만 호출되면 문제가 없다.
하지만 `hash(into:)`는 `Hashable` 프로토콜 requirement다. Swift는 이 requirement를 일반 동기 메서드 형태로 만족하기를 기대하는데, actor의 인스턴스 메서드는 기본적으로 actor-isolated다.
그래서 `hash(into:)`를 actor-isolated 인스턴스 메서드로 두면, `actor-isolated instance method 'hash(into:)' cannot be used to satisfy a protocol requirement` 같은 제약이 발생한다. 즉 핵심은 “내부에 정의했느냐”가 아니라 “프로토콜 요구사항이 어떤 호출 계약을 요구하느냐”다.
글 문맥에서는 `==` 비교는 `static` 메서드로 작성하고, 비교 기준을 immutable한 `let accountNumber` 같은 값으로 제한하면 `Equatable`은 채택할 수 있음을 보여 준다.
반면 `Hashable`의 `hash(into:)`는 인스턴스 메서드 requirement라서 상황이 다르다. 결국 actor의 API를 어디까지 일반 value type처럼 다룰 수 있는지에 제약이 생긴다.
일반 함수나 computed property는 원래 actor 바깥 문맥이다. 그래서 actor 파라미터를 그냥 받으면 그 actor의 isolated 상태를 본문에서 직접 읽거나 수정할 수 없다.
func deposit(amount: Double, to account: BankAccount) {
account.balance = account.balance + amount // error
}여기서 `account`를 `isolated`로 표시하면 함수 전체가 `account` actor의 isolation context 안에서 실행되는 것처럼 취급된다. 그러면 본문에서 `account.balance`를 직접 쓸 수 있다.
func deposit(amount: Double, to account: isolated BankAccount) {
assert(amount >= 0)
account.balance = account.balance + amount
}즉 정리는 이렇다. “원래는 직접 못 쓰기 때문에, actor 파라미터 상태를 함수 본문에서 직접 다루고 싶어서 `isolated`를 붙인다.”