참고: 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 키워드를 붙여준다!
혹시 다른 어떤 의견이 있으신 분은 댓글 남겨주세요!