프로토콜

박형석·2021년 11월 29일
0

Swift

목록 보기
2/20
post-thumbnail
post-custom-banner

프로토콜이란?

  • 특정 역할을 하기 위한 메서드, 프로퍼티, 기타 요구사항 등의 청사진
    정의 & 제시할 뿐 스스로 기능을 구현 X
  • 채택(Adopted) / 준수(Conform)
  • 채택시 청사진의 기능을 모두 구현(준수)해야 한다.
  • 여러 프로토콜 채택 가능
  • 구현시 상속이 있는 경우 제일 앞에.
protocol 이름 : AnotherProtocol, AnotherProtocol {
 // 정의
}
class SomeClass : SuperClass, AnotherProtocol, AnotherProtocol {
 // 정의
}

프로토콜 요구사항

채택하는 타입이 특정 기능을 실행하기 위해 필요한 기능을 요구한다.

  1. 프로퍼티 요구

    • 구현 : 이름과 타입 + 읽기 전용 / 읽기 쓰기
    • 프로퍼티 종류는 중요하지 않음(연산인지 저장인지)
    • 읽기 전용은 당연히 let이나 연산 프로퍼티도 가능 { get }
    • 읽기 쓰기는 당연히 let이나 연산은 안됌 { get set }
    • 쓰기 전용은 없음
    • 타입 프로퍼티는 static → 나중에 준수할 때 상속 가능한 class type인지 불가능한 static type인지 구분
protocol SomeProtocol {
 var settableProtocol: String { get }
 var notNeedProtocol: String { get set }
 static var somProperty: Int { get set }
}
  1. 메서드 요구

    • 이름, 매개변수, 반환 타입을 작성 { 중괄호 제외 } (가변 매개변수 허용)
    • 마찬가지로 인스턴스 메서드, 타입 메서드(static → 구현시 class, static 구분)를 요구할 수 있음
    • 가변 메서드 요구 : 메서드가 인스턴스 내부의 값을 변경할 필요가 있을 때. mutating을 준수해줘야 한다. 물론 구조체나 열거형일 때. 만약 안하면 수정 불가능하다.
    protocol SomeProtocol {
     func deletePost(postID: String) -> Bool
     static func isDeletableInstance(_ instance: Any) -> Bool
     mutating func resetBookmark()
    }
    • 이니셜라이저 요구 : 역시 정의만하고 구현하지 않는다
      • 구조체는 상속할 수 없기 때문에 이니셜라이저 요구에 대해 신경X
      • 이니셜라이저가 Designated인지 Convinence인지 중요 X
        → 다만 구현할 때 required 식별자를 붙이고 구현해야 한다. (상속받는 클래스도 모두 구현해야 하기 때문에 )
        → 그럼 final class라면? required 안붙여도 된다.
      • 프로토콜을 요구하는 이니셜라이저가 이미 구현되어 있는 클래스?
        → required override init() { }
      • 실패 가능한 이니셜라이저
        → 실패 가능한 이니셜라이저 or 일반적인 이니셜라이저 구현 둘 다 무방
  1. 프로토콜의 상속과 클래스 전용 프로토콜
    - 프로토콜 상속 : 상속 + 상속 + 상속... = 3개의 기능 모두 추가. 작은 단위 → 큰 기능 가능
    - 프로토콜 상속 리스트에 class 키워드 추가 → class 타입에만 채택될 수 있게 제한(제일 앞에 위치)

    protocol Readable {
     func read()
    }
    
    protocol Writable: class, Readable {
     func write()
    }
    
    // 클래스라 채택 가능
    class SomeClass: Writhable {
     func read() { }
     func write() { }
    }
  2. 프로토콜 조합과 프로토콜 준수 확인

    • 하나의 매개변수가 여러 프로토콜을 모두 준수하는 타입이어야 한다면 조합(Composition)하여 요구할 수 있음 : SomeProtocol & AnotherProtocl & ... 이렇게

    • 클래스 인스턴스 역할을 할 수 있는지와 함께 확인할 수 있다. 구조체 열거형 안되고 클래도 한 타입만 조합 가능

    • is나 as로 타입을 확인하거나 캐스팅 할수 있다.

      protocol Name {
       var name: String { get }
      }
      
      protocol Aged {
       var age: Int { get }
      }
      
      class Car: Named {
       var name: String
       init(name: String) {
        self.name = name
       }
      }
      
      class Truck: Car, Aged {
       var age: Int
       init(age: Int) {
        self.age = age
       }
      }
      
      // 클래스 역할도 할 수 있고 Aged 프로토콜도 준수하므로 할당할 수 있따. 
      var someVehicle: Car & Aged?
      someVehicle = Truck(name: "Tank", age: 14)
  1. 프로토콜의 선택적 요구

    • 프로토콜의 요구사항 중 일부를 선택적 요구사항으로 지정할 수 있음 → 필수로 구현X
    • objc 속성이 부여된 프로토콜이라야 가능 → objc 클래스를 상속받은 클래스에서만 채택 가능(구조체, 열거형 X) → objc 클래스 상속을 받는 클래스 == NSObject를 상속
    • objc를 사용하기 위해서 Foundation import
    • 선택적 프로토콜 식별자(optional)가 붙은 프로토콜은 자동으로 옵셔널이 된다. (반환 값이 아닌 자기 자신이...)
    • 옵셔널이기 때문에 옵셔널 체이닝으로 호출할 수 있음.
    @objc protocol Movable {
     func walk()
     @objc optional func fly()
    }
    
    class Tiger: NSObject, Movable {
     func walk() { }
    }
    
    let tiger = Tiger()
    tiget.fly?()
  1. 프로토콜 변수와 상수

    • 프로토콜 이름을 타입으로 갖는 변수와 상수에는 그 프로토콜을 준수하는 타입의 어떤 인스턴스라도 할당할 수 있다.
    • 프로토콜 이름만으로 자기 스스로 인스턴스 생성, 초기화는 불가능 하지만 프로토콜을 준수하는 타입의 인스턴스를 할당할 수는 있음.
  2. 위임을 위한 프로토콜

    • 위임 : 클래스나 구조체가 자신의 책임이나 의무를 다른 타입의 인스턴스에게 위임하는 디자인 패턴
    • 애플의 프레임워크에서 사용하는 주요한 패턴 중 하나. 디자인 패턴. ~~~ Delegate

타입으로서의 프로토콜 사용

프로토콜은 완전한 하나의 타입으로 사용되기에 여러 위치에서 프로토콜을 타입으로 사용할 수 있다. 그래서

  • 함수, 메서드, 이니셜라이저에서 매개변수 타입이나 반환 타입으로 사용 가능
  • 프로퍼티, 변수, 상수 등의 타입으로 사용 가능
  • 베얄, 딕셔너리 등 컨테이너 요소의 타입으로 사용 가능
  • 위에서 이야기했듯 인스턴스 생성은 불가능
profile
IOS Developer
post-custom-banner

0개의 댓글