클래스의 이니셜라이져는 Designated Initializer, Convenience Initializer 이렇게 2가지로 분류된다. 각각 Initializer들이 가지고 있는 고유한 특성은 분명한 차이를 보인다. 아래의 박스를 보자.
1. Designated Initializer
Designated Initializer 는 우리말로 지정생성자로 불리우며, 클래스의 메인생성자이다. 모든 속성을 반드시 초기화시켜야 하며, 만약 SuperClass로 부터 상속을 받은 클래스라면 생성자의 실행이 완료되기 전에 SuperClass의 지정생성자를 호출해야 한다. 구현할 수 있는 수의 제한은 없지만 보통 하나만 구현한다.
2. Convenience Initializer
Convenience Initializer 는 우리말로 편의생성자로 불리우며, 보통 지정생성자나 편의생성자의 필요한 속성 몇가지만 초기화한 다음, 클래스에 있는 다른 이니셜라이져를 호출하여 나머지 속성을 초기화 할 때 사용한다. 이때 호출하는 생성자는 반드시 동일한 계층에 있는 지정생성자나 편의생성자여야 한다. 여기서 한가지 더 주의해야 할 점은 동일한 계층의 편의생정자를 호출하더라도 그 호출한 편의생성자는 최종적으로 동일한 클래스내에 지정생성자를 호출해야 한다는 것이다.
ex)
class Position {
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
convenience init(x:Double) {
self.init(x: x, y:0.0)
}
}
* 보다시피 지정생성자는 모든 속성을 초기화하고 있으며, 편의생성자는 코드의 중복을 피하기 위해 지정생성자를 호출한 뒤, x에는 파라미터를 그대로 전달하고, y에는 기본값을 전달하고 있다.
* 클래스의 생성자는 원칙적으로 상속이 불가능하다. 그러나 다음 2가지 규칙 아래에 상속이 자동으로 이루어진다.
서브클래스 모든 속성이 기본값으로 초기화 되어 있고 이니셜라이져를 구현하지 않았다면 슈퍼클래스에 있는 모든 이니셜라이즈가 상속된다.
서브클래스가 모든 이니셜라이져를 상속받았거나 오버라이딩 했다면, 모든 편의생성자가 상속된다.
ex)
class Person {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "unknown")
}
}
class Information: Person {
var weight: Double = 0.0
var height: Double = 0.0
init(name: String, weight: Double, height: Double) {
self.weight = weight
self.height = height
super.init(name: name)
}
override init(name: String) {
weight = 0.0
height = 0.0
super.init(name: name)
}
convenience init() {
self.init(name: "unknown")
}
}
* 보다시피 SubClass의 지정생성자에서 현재 계층의 모든 속성을 초기화 한 뒤에 SuperClass의 지정생성자를 호출함과 동시에 나머지 속성을 초기화하고 있다. 그리고 편의생성자는 지정생성자의 특정 속성을 초기화 한뒤 동일한 계층의 생성자를 호출하고 있다. 이는 재정할때도 동일한 규칙을 따른다. 그러나 코드를 보고 있으면 한가지 의문이 생긴다. 현재 위의 코드에서는 지정생성자를 재정의해주었는데, 편의생성자를 재정의하는 것도 가능한가?
* 답은 No다. 편의생성자는 항상 동일한 클래스에 있는 다른 생성자를 호출해야하며 최종적으로 동일한 클래스의 지정생성자를 향해야 한다. 그렇다는 것은 편의생성자의 행동 범위는 현재 계층으로 국한 된다는 것이다. 그러한 이유로 재정의라는 개념은 적용되는 것이 불가능하다.