초기화 위임(Initializer Delegation)은 스위프트에서 클래스의 초기화 과정을 위한 체계로 내장되어 있습니다. 스위프트는 기본 초기화자(designated initializer, 클래스의 모든 속성을 완전히 초기화할 책임이 있는 주요 초기화자)와 편리 초기화자(convenience initializer, 다양한 매개변수 세트를 사용하여 인스턴스를 생성하는 데 도움을 주는 보조 초기화자) 간에 역사적으로 구분이 있습니다.
문제: 클래스와 그 상속자 사이에서 초기화자가 무질서하게 실행될 경우, 기본 클래스가 완전히 초기화되지 않거나 초기화가 한 번 이상 진행되는 상황이 발생할 수 있으며, 이로 인해 잘못된 객체가 생성될 수 있습니다.
해결책 — 엄격한 규칙:
코드 예시:
class Vehicle { var wheels: Int // Designated initializer init(wheels: Int) { self.wheels = wheels } // Convenience initializer convenience init() { self.init(wheels: 4) } } class Car: Vehicle { var color: String // Designated initializer init(wheels: Int, color: String) { self.color = color super.init(wheels: wheels) } // Convenience initializer convenience init(color: String) { self.init(wheels: 4, color: color) } }
주요 특징:
질문 1: convenience initializer가 직접 super.init을 호출할 수 있습니까?
아니요, convenience initializer는 항상 현재 클래스의 다른 초기화자에게 초기화를 위임하며, 그 이후에 슈퍼클래스의 designated initializer를 호출할 수 있습니다.
질문 2: 서브클래스에서 required 초기화자를 구현하지 않으면 어떻게 됩니까?
슈퍼클래스에 required 초기화자가 있는 경우, 반드시 모든 서브클래스에서 이를 오버라이드해야 하며(필요한 경우 required 사용), 그렇지 않으면 컴파일러 오류가 발생합니다.
질문 3: convenience init과 convenience required init의 차이점은 무엇입니까?
convenience required init은 특정 convenience 초기화자가 슈퍼클래스에서 required로 선언된 경우, 상속 계층에서 초기화 지원을 보장하기 위해 필요합니다.
개발자가 convenience 초기화자에서 super.init을 호출했습니다. 코드는 특정 제약이 없었기 때문에 컴파일되었으나, 실행 시 객체의 모든 속성이 초기화되지 않아 오류가 발생했습니다.
장점:
단점:
디자인된 초기화자와 convenience 초기화자를 명확히 구조화하여 서로를 명시적으로 호출했습니다. 로직이 스위프트 규칙에 따라 엄격하게 작동했기 때문에 초기화가 항상 투명하고 올바르게 이루어졌습니다.
장점:
단점: