이 포스트는 야곰님의 Swift 프로그래밍 2판을 보고 스스로 공부한 내용을 정리한 포스트 입니다.


예제 코드


참고 자료


가변 메서드 요구 (Mutating Method Requirements)

  • 값 타입(구조체, 열거형)의 인스턴스 메서드에서 자신 내부의 값을 변경하고자 할 때는 메서드의 'func' 키워드 앞에 'mutating' 키워드를 적어 메서드에서 인스턴스 내부의 값을 변경한다는 것을 확실히 해준다.

  • 프로토콜이 어떤 타입이든 간에 인스턴스 내부의 값을 변경해야 하는 메서드를 요구하려면 프로토콜의 메서드 정의 앞에 'mutating' 키워드를 명시해야 한다.

  • 참조 타입인 클래스의 메서드 앞에는 'mutating' 키워드를 명시하지 않아도 인스턴스 내부 값을 바꾸는 데 문제가 없다.

  • 값 타입인 구조체와 열거형의 메서드 앞에는 'mutating' 키워드를 붙인 가변 메서드 요구(Mutating Method Requirements)가 필요하다.

  • 프로토콜에 'mutating' 키워드를 사용한 메서드 요구가 있다고 하더라도 클래스 구현에서는 'mutating' 키워드를 써주지 않아도 된다.

protocolExampleImage-7

  • Resettable 프로토콜reset()이라는 가변 메서드를 요구한다.

  • Resettable 프로토콜을 채택한 Person 클래스에는 'mutating' 키워드를 제외하고 'reset()' 메서드를 구현했다.

  • Resettable 프로토콜을 채택한 값 타입인 Point 구조체와 Direction 열거형'mutating' 키워드를 포함하여 구현했다.

  • '만약 Resettable 프로토콜에서 가변 메서드를 요구하지 않는다면, 값 타입의 인스턴스 내부 값을 변경하는 mutating 메서드는 구현이 불가능하다'


이니셜라이저 요구

  • 프로토콜은 프로퍼티, 메서드 등과 마찬가지로 특정한 이니셜라이저를 요구할 수도 있다.

  • 프로토콜에서 이니셜라이저를 요구하려면 메서드 요구와 마찬가지로 이니셜라이저를 정의하지만 구현은 하지 않는다.

    • 즉, 이니셜라이저의 매개변수를 지정하기만 할 뿐, 중괄호를 포함한 이니셜라이저 구현은 하지 않는다.

protocolExampleImage-8

  • 위 코드의 Pet 구조체는 Named 프로토콜을 채택하여 요구 프로퍼티와 이니셜라이저를 모두 구현했다.

protocolExampleImage-9

  • 구조체는 상속할 수 없기 때문에 이니셜라이저 요구에 대해 크게 신경쓸 필요가 없지만 클래스의 경우라면 조금 다르다.

  • 클래스 타입에서 프로토콜의 이니셜라이저의 요구에 부합하는 이니셜라이저를 구현할 때는 이니셜라이저가 지정 이니셜라이저인지 편의 이니셜라이저인지는 중요하지 않다.

    • 그러나 이니셜라이저 요구에 부합하는 이니셜라이저를 구현할 때는 'required' 식별자를 붙인 '요구 이니셜라이저'로 구현해야 한다.
  • 위의 코드의 Person 클래스를 상속받는 모든 클래스는 'Named' 프로토콜을 준수해야 하며, 이는 곧 상속받는 클래스에 해당 이니셜라이저를 모두 구현해야 한다는 뜻이다.

    • 그렇기 때문에 Named에서 요구하는 init(name:) 이니셜라이저를 'required' 식별자를 붙인 '요청 이니셜라이저'로 구현해야 한다.

protocolExampleImage-10

  • 만약에 '클래스 자체가 상속받을 수 없는 final 클래스'라면 'required' 식별자를 붙여줄 필요가 없다.

    • 상속할 수 없는 클래스와 요청 이니셜라이저 구현은 무의미하기 때문이다.

protocolExampleImage-11

  • 만약 특정 클래스에 프로토콜이 요구하는 이니셜라이저가 이미 구현되어 있는 상황에서 그 클래스를 상속받은 클래스가 있다면, 'required'와 'override' 식별자를 모두 명시하여 프로토콜에서 요구하는 이니셜라이저를 구현해주어야 한다.

  • 위의 코드에서 School 클래스는 Named 프로토콜을 채택하지 않았지만 Named 프로토콜이 요구하는 이니셜라이저가 이미 있는 상태이다.

    • 그런데 MiddleSchool 클래스는 School 클래스를 상속받았으며, Named 프로토콜을 채택했다.

    • 그래서 School 클래스에서 상속받은 init(name:) 이니셜라이저를 재정의해야 하며 동시에 Named 프로토콜의 이니셜라이저 요구도 충족시켜주어야 한다.

    • 그래서 'override'와 'required' 식별자를 모두 표기해야 한다.

    • 두 식별자 중 어떤 것이 먼저 위치해도 상관 없다. 즉, 식별자의 표기 순서는 상관 없다는 뜻이다.


실패 가능한 이니셜라이저 요구

protocolExampleImage-12re

  • 프로토콜은 일반 이니셜라이저 외에도 '실패 가능한 이니셜라이저'를 요구할 수도 있다.

  • 실패 가능한 이니셜라이저를 요구하는 프로토콜을 준수하는 타입은 해당 이니셜라이저를 구현할 때 실패 가능한 이니셜라이저로 구현해도, 일반적인 이니셜라이저로 구현해도 무방하다.