프로토콜에서 이니셜라이저를 정의했을 때

init(coder:) 가 정의되지 않았다는 에러

UIView, UIViewController를 서브클래싱하는 코드를 작성하면서 init(frame:)을 오버라이딩하는 코드를 작성하면, Xcode는 매번 init?(coder:)가 정의되지 않았다는 컴파일 에러를 낸다. 이 에러를 해결하려면 간단하게 부모 클래스의 이니셜라이저를 그대로 호출해주기만 하면 된다.

required init?(coder aDecoder: NSCoder!) {
    super.init(coder: aDecoder)
}

실질적으로는 부모의 이니셜라이저를 재호출할 뿐인데 왜 이 녀석은 상속받지 못하고 매번 사람을 귀찮게 하는가?

NSCoding

스토리보드 및 nib 파일로부터 불러올 수 있는 클래스들은 바이너리 (혹은 프로퍼티 리스트) 파일로부터 읽어들인 데이터로부터 역직렬화를 통해서 객체 그래프를 복원하게 된다. 이 때 사용되는 프로토콜이 NSCoding이고, NSCoding은 인코더를 통해서 직렬화하고 디코더를 통해서 복원이 가능하다는 맥락이므로, 프로토콜 내에 designated initializerinit?(coder:)를 정의해두었다.

Swift에서 프로토콜에서 designated initializer를 정의하면 이를 따르는 클래스는 해당 이니셜라이저를 반드시 제공해야 하며, 이는 이니셜라이저에 required가 붙게된다. required가 붙게되면 해당 이니셜라이저는 반드시 구현되어야 하고, 해당 클래스의 서브 클래스들 역시 이를 제공해야 한다.

왜 이런 required가 붙는 이니셜라이저가 필요할까? Swift는 Objective-C와 달리 서브 클래스가 부모 클래스의 모든 이니셜라이저를 상속하지 않는다. (사실 Objective-C에서의 이니셜라이저는 일반적인 메소드와 차이가 없다.) 이는 서브 클래스에서 새로 도입된 프로퍼티의 초기화는 해당 클래스에서 온전히 책임지며, 상속받은 프로퍼티는 부모 클래스의 이니셜라이저를 통해서만 초기화할 수 있게끔하는 규칙 때문이다. 만약 부모 클래스가 2개 이상의 지정 이니셜라이저를 가지고 있을 때, 자식 클래스가 그 중 1개의 지정 이니셜라이저만 오버라이딩하거나, 혹은 제 3의 지정 이니셜라이저를 새로 구현하는 경우 나머지 이니셜라이저들은 상속되지 않는다.

UIViewControllerUIViewNSCoding을 따르고 있고, 따라서 required init(coder:)라는 이니셜라이저를 가지고 있을 것이다. 만약 이들의 서브 클래스를 작성한다고하면 자식 클래스 역시 NSCoding을 따르는 조건을 상속하게 된다. 이 때 새로운 이니셜라이저를 작성하거나 init(frame:)을 오버라이딩하면 required가 붙는 이니셜라이저들은 상속되지 못하게 되고 컴파일러는 클래스 구현이 완전하지 않다는 에러를 표시한다.

Swift에서 클래스의 이니셜라이저 작성과 관련된 내용은 다음 기회에 추가로 정리해봐야겠다.