본문 바로가기
Swift/Basic

Generic, Protocol

by songmoro 2024. 11. 7.
728x90

Generic

  • 요구 사항에 따라 모든 타입에서 동작하는 유연하고, 재사용 가능한 함수 및 타입을 작성 가능
  • 제네릭이 해결하는 문제
    • 특정 타입에 의존하지 않고, 모든 타입에서 작동하는 범용적인 코드 작성 가능
    • 예를 들어, swapTwoInts라는 메소드는 Int라는 타입에 의존적임
      • 제네릭을 사용하면 타입 매개변수가 호출 시점에 지정한 타입으로 변환됨
  • 함수의 매개변수로 Int, String과 같은 타입이 아닌 타입 매개변수를 사용함
    • 타입 매개변수는 함수의 전달 값의 타입에서 추론됨
  • 프로토콜 정의
    • 프로토콜을 정의할 때 제네릭을 사용하고 싶다면 associatedtype 사용
    • 채택하는 측에선 typealias

 

Protocol

  • 프로토콜은 타입
  • 특정작업 또는 기능에 적합한 메소드, 속성을 정의하는 방법
  • 클래스, 구조체, 열거형에 의해 채택되어 요구 사항의 실제 구현을 제공
    • 프로토콜의 요구 사항을 충족하는 타입은 해당 프로토콜을 준수한다고 함
  • 프로토콜은 타입이기 때문에 다른 타입(Int, String, ...)과 같이 대문자로 시작
  • 인스턴스 속성 또는 타입 속성을 제공하기 위해 준수 타입 요구
    • stored 속성, computed 속성인지 지정하지 않고, 속성 이름과 타입만 지정
    • 대신 gettable, settable을 지정
  • 프로토콜을 타입으로 사용하는 방법
    • 프로토콜은 실제 기능을 구현하지 않지만, 다른 타입들이 프로토콜을 따르게 할 수 있다.
      • 이로 인해 프로토콜을 타입처럼 사용할 수 있음
    • Generic 제약으로 사용
      • 특정 프로토콜을 준수하는 모든 타입에 대해 동작
      • 호출자가 사용할 타입을 결정
    • 불투명(Opaque) 타입으로 사용
      • 구체적인 타입은 숨기고, 프로토콜 준수 여부만 보장
      • API 구현이 타입을 결정하고, 추상화 계층을 유지
    • 박스형(Boxed) 프로토콜 타입으로 사용
      • 런타임에서 동적으로 다양한 타입과 동작
      • 오버헤드가 발생하지만 유연성을 제공
  • 프로토콜 클래스로 제한
    • AnyObject 프로토콜을 프로토콜의 상속으로 추가하면 프로토콜을 상속받는 타입을 클래스 타입으로 제한할 수 있음
  • extension generic 제약
    • where를 통해 메소드가 속성을 사용하기 위한 조건을 지정할 수 있음

Opaque Type, Boxed Protocol Type

  • 값 타입에 대한 세부 구현 정보를 추상화하는 방법
  • Swift는 값 타입에 대한 세부 정보를 숨기는 방법을 두 가지 제공
    • 불투명 타입(opaque type), 박스형 프로토콜 타입(boxed protocol type)
  • 반환 값의 타입이 비공개로 유지될 수 있기 때문에 유용
    • 모듈과 모듈을 호출하는 코드의 경계에서 타입 정보를 숨길 수 있음
  • 불투명 타입
    • 반환 값의 타입을 숨김
    • 메서드의 반환 타입으로 구체적인 유형을 제공하지 않고, 프로토콜의 관점에서 설명
    • 타입 identity를 보존
      • 컴파일러는 타입 정보에 액세스할 수 있지만, 모듈의 클라이언트는 그렇지 않다.
  • 박스형 프로토콜 타입
    • 주어진 프로토콜을 준수하는 모든 타입의 인스턴스를 저장할 수 있음
    • 타입 identity를 보존하지 않음
      • 값의 특정 타입은 런타임까지 알려지지 않는다.
        • 다른 값이 저장됨에 따라 시간이 지나면 변할 수 있다.
  • 불투명 타입이 해결하는 문제
    • 메서드가 특정 타입을 반환하면서도, 구체적인 타입을 외부에서 알 수 없도록 숨길 수 있음
      • 추상화 수준을 높이고, 구현 세부 사항을 감춘다.
      • 모듈의 내부 구조를 노출하지 않으며 원하는 결과 제공
    • 제네릭으로 구현하면 구체적인 타입이 드러나는 문제가 있다.
      • 내부 타입은 모듈 사용자가 알 필요 없음
      • 모듈의 세부 구현이 외부로 노출되는 문제 발생
    • some 키워드 사용
      • some Type을 반환해 구체적인 타입을 숨기며 Type 프로토콜을 준수한다고 보장
    • 제네릭 vs 불투명
      • 제네릭 타입: 호출자가 구체적인 타입 지정
      • 불투명 타입: 함수 구현에서 구체적인 타입 지정, 외부에 숨김
    • 제네릭 with 불투명
      • 불투명 타입과 제네릭 타입을 결합하여 사용 가능
        • 불투명 타입을 반환하지만, 내부적으로 제네릭으로 구현해 유연한 사용 가능
    • 여러 반환 타입 불가
      • 불투명 타입을 반환할 때는 반환 타입이 하나로 고정되어야 함
      • 여러 타입을 반환할 경우 Swift는 불투명 타입을 사용할 수 없음
  • 박스형 프로토콜 타입이 해결하는 문제
    • any 키워드 사용
    • 프로토콜을 준수하는 여러 타입의 값을 하나의 컬렉션이나 변수에 저장할 수 있게 함
      • boxed란 런타임에 타입이 결정되며 Swift가 필요할 때마다 간접 참조로 실제 타입을 관리하는 것
      • 이로 인해 오버헤드 발생 가능
      • 각 요소는 특정 프로토콜을 준수하지만 구체적으로 어떤 타입이던 혼합하여 저장 가능
    • 장단점
      • 장점
        • 서로 다른 타입의 값을 한 변수에 저장할 수 있어 유연성 제공
        • 특정 프로토콜을 준수하므로, 프로토콜의 메서드와 속성 사용 가능
      • 단점
        • 프로토콜에 정의되지 않은 메서드나 속성 접근 불가
        • 프로토콜을 인자로 받아야 하는 함수에 중첩 사용 불가
  • 박스형 프로토콜 vs 불투명
    • 박스형 프로토콜
      • 여러 타입 허용
      • 런타임에 동적으로 타입 결정
      • 반환 타입 고정으로 타입 일관성 보장
    • 불투명
      • 단일 타입 반환
      • 구체적인 타입 숨김
      • 컴파일 시점에 타입 결정
      • 다른 타입 반환으로 유연성 높지만 일관성 떨어짐
728x90

'Swift > Basic' 카테고리의 다른 글

프로젝트가 프로세스가 되기까지 - 2  (0) 2024.12.18
프로젝트가 프로세스가 되기까지 - 1  (1) 2024.12.06
Data Type  (0) 2024.11.07
Concurrency  (0) 2024.11.07
GCD  (0) 2024.10.31