프로그래밍시니어 iOS 개발자

'불투명 타입' (some)은 Swift에서 무엇이며, 언제 그리고 왜 사용하며, associated type이 있는 프로토콜과의 차이점은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사:

Swift 5 이전 버전에서는 associated type이 있는 프로토콜에 해당하는 값을 반환할 때 종종 제한에 직면했습니다. return type으로 직접 사용할 수 없었고 type erasure가 필요했습니다. 가독성과 성능을 향상시키기 위해 '불투명 타입'이 도입되었습니다. 이는 some 키워드를 통해 반환되는 값으로, 공용 인터페이스에서 추상화를 설명할 수 있게 합니다.

문제:

실제 반환 타입을 숨기되 프로토콜을 통해 추상을 유지하고자 할 때 발생합니다. 그러나 dynamic dispatch와 type erasure의 비용을 피하고자 할 때 필요합니다. 예를 들어, 컬렉션, 시퀀스, 뷰 컴포넌트를 반환할 때가 있습니다.

해결책:

불투명 타입은 프로토콜에 해당하는 타입을 반환하면서 그 구체적인 구현을 숨길 수 있습니다. 컴파일러는 실제 타입을 알고 있지만 호출하는 쪽은 알지 못합니다.

예시:

protocol Shape { func area() -> Double } struct Circle: Shape { var radius: Double func area() -> Double { Double.pi * radius * radius } } func makeCircle() -> some Shape { return Circle(radius: 3) } let s = makeCircle() print(s.area()) // 작동합니다

주요 특징:

  • 불투명 타입은 항상 프로토콜에 의해 감춰진 동일한 타입입니다. some을 통해 반환됩니다.
  • type erasure보다 빠르고 더 엄격하며, 프로토콜 내의 associated type과 함께 작업할 수 있습니다.
  • 다른 분기에서 서로 다른 타입을 반환할 수 없습니다 (모든 return에 대해 타입이 동일해야 합니다).

질문과 트릭.

불투명 타입 (some Protocol)은 반환되는 프로토콜 타입과 무엇이 다릅니까?

불투명 타입은 컴파일 시 구체적인 구현을 가집니다 (외부에서 숨겨져 있지만). Protocol을 반환할 때는 dynamic dispatch가 작동하며, associated type이 있을 경우 type safety가 없습니다.

some Protocol을 사용하여 하나의 함수에서 서로 다른 타입을 반환할 수 있나요?

아니요. 모든 return은 동일한 실제 타입을 반환해야 합니다:

func maker(flag: Bool) -> some Shape { if flag { return Circle(radius: 3) } else { return Square(size: 2) // 오류: 반환 타입이 일치하지 않음 } }

프로토콜 내의 associatedtype은 some Protocol을 통해 사용할 수 있나요?

네. 바로 이것을 위해 (주로) 불투명 타입이 필요합니다:

protocol View { associatedtype Body } func makeView() -> some View { /* ... */ }

일반적인 오류와 안티 패턴

  • some Protocol과 Protocol을 혼동 — 서로 다른 케이스와 제한 사항이 있습니다.
  • 모든 분기에서 반환 타입의 균일성 규칙을 위배.
  • 더 간단한 경우에 some을 사용하는 경향.

실생활의 예

부정적인 사례

함수가 불투명 없이 프로토콜을 반환하여 associated type에 대한 메서드를 사용할 수 없고, 복잡한 type erasure가 필요하며, 코드는 컴파일되지 않거나 비효율적으로 작동합니다.

장점:

  • AnySequence와 같은 타입 추상화의 유연성.

단점:

  • type safety의 손실, 낮은 성능.
  • associated type이 작동하지 않음.

긍정적인 사례

SwiftUI의 ViewBuilder는 some View를 사용하여 세부 정보를 숨기고 타입 안전성을 높이며 컴파일 및 런타임 속도를 향상시킵니다.

장점:

  • 읽기 쉬운 API, type safety, dynamic dispatch 없음.
  • 유지 보수의 용이함.

단점:

  • 하나의 함수에서 서로 다른 타입을 반환할 수 없음.