참고: https://forums.swift.org/t/why-does-swift-need-the-convenience-keyword/55428
Initializer의 상속이 있는 다른 언어들과, Swift의 차이가 존재상위클래스 이니셜라이저의 subset(하위집합)을 자동으로 상속해서 가져옴.하위 클래스에서 상위 클래스의 이니셜라이저를 호출함으로서 상위 클래스의 저장속성들을 초기화 해야 함하위 클래스에서는 상위 클래스의 이니셜라이저가 다른 이니셜라이저를 호출하는지 아닌지를 알 수 없다.convenience 키워드를 붙여줌으로서 하위 클래스에서 다른 이니셜라이저를 호출하지 않는, 해당 단계의 저장 속성을 모두 초기화하는 지정 이니셜라이저를 호출하게 하는 것.convenience 키워드가 없다면?convenience 키워드는 현재 단계의 이니셜라이저만, 현재 단계에서만 호출 할 수 있게 함
만약 하위 클래스에서 상위 클래스의 convenience 이니셜라이저를 호출할 수 있다면??
class SuperClass {
var name: String
init() { self.init(name: "name") } // convenience 키워드를 붙이지 않았음.
init(name: String) { self.name = name }
}
class SubClass: SuperClass {
override init(name: String) { super.init() } // 상위 클래스의 init을 호출
}
let subClass = SubClass(name: "name")
❓https://jercy.tistory.com/2 블로그에서는, “위와같이 호출할경우 무한루프에 빠질수 있습니다.”
라고 하는데, 왜 무한루프에 빠지지??
- SubClass 의 init(name:) 호출 → SuperClass의 init() 호출 → SuperClass의 init(name:) 호출??
final 키워드로 상속을 불가하게 한다면? 어떤 차이가 있을까?class SuperClass {
var name: String
init(name: String) {
self.name = name
self.printText()
}
func printText() {
print("SuperClass printText")
}
}
class SubClass: SuperClass {
override init(name: String){
super.init(name: name)
}
override func printText() {
print("SubClass printText")
}
}
let subClass = SubClass(name: "name")
SubClass 의 init(name:) → SuperClass 의 init(name:) 호출.class A {
init(x: Int) {
print("A.init(x:)")
}
convenience init(y: Int) {
print("A.init(y:)")
self.init(x: y)
}
}
class B: A {
override init(x: Int) {
print("B.init(x:)")
super.init(y: x)
}
}
B(y: 0) // A.init(y:) -> B.init(x:) -> A.init(x:)...
// Allowing `B.init(x:)` to call `A.init(y:)` will cause an infinite loop.
즉 정리하자면,
상속 구조에서는 메서드 디스패치 (테이블디스패치)가 적용되고,
하위 클래스에서 상위클래스의 편의생성자를 호출한다면
해당 상위클래스의 편의생성자에서 상위클래스의 지정생성자를 호출할 때 해당 생성자를 하위 클래스에서 오버라이드 한 생성자가 호출 할 수 있기 때문에 무한 루프에 빠질 수 있다"
그렇기 때문에 하위 클래스의 생성자에서 상위클래스의 지정생성자를 호출하도록 강제해야 하고,
지정생성자와 편의생성자를 구분짓기 위해 convenience 키워드를 붙여준다!
혹시 다른 어떤 의견이 있으신 분은 댓글 남겨주세요!