지난 글에서는 지정 이니셜라이저와 편의 이니셜라이저, 그리고 초기화 단계에 대해 살펴보았다.
여기서는 이니셜라이저의 상속에 관해 다루려고 한다.
그럼 시작
이니셜라이저의 상속 및 재정의
기본적으로 스위프트의 이니셜라이저는 부모 클래스의 이니셜라이저를 상속받지 않는다.
> 부모 클래스로부터 물려받은 이니셜라이저는 자식 클래스에 최적화되어 있지 않아서, 부모 클래스의 이니셜 라이저를 사용했을 때 자식 클래스의 새로운 인스턴스가 완전하고 정확하게 초기화되지 않는 상황을 방지하고자 함
> but, 안전하고 적절하다고 판단되는 특정한 상황에서는 예외 케이스도 존재함 그건 밑에서 다룰 예정
부모 클래스와 동일한 지정 이니셜라이저를 자식 클래스에서 구현해주려면 재정의하면 됨
방법은 간단하다. init 앞에 override 키워드만 붙여주면 된다.
자식 클래스의 편의 이니셜라이저가 부모 클래스의 지정 이니셜라이저를 재정의하는 경우에도 똑같이 해주면 된다. (ex. override convenience init)
그럼 자식 클래스에서 부모 클래스의 편의 이니셜라이저를 구현하려면 어떻게 해야 할까?
답은 자식 클래스에서 부모 클래스의 편의 이니셜라이저는 호출 자체가 불가능하다. 즉, 재정의할 필요가 없음
예제로 확인해 보자
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init(name: String) {
self.init(name: name, age: 0)
}
}
class Student: Person {
let major: String
override init(name: String, age: Int) { // 1
self.major = "Computer Engineering"
super.init(name: name, age: age)
}
convenience init(name: String) { // 2
self.init(name: name, age: 10)
}
}
- 부모 클래스의 지정 이니셜라이저 재정의를 위해 override 키워드를 사용한 것을 확인할 수 있다.
- 반대로 자식 클래스에서 부모 클래스와 동일한 편의 이니셜라이저 구현 시, override 키워드를 사용하지 않는 것을 볼 수 있음
이니셜라이저 자동 상속
위에서 기본적으로 스위프트의 이니셜라이저는 부모 클래스의 이니셜라이저를 상속받지 않는다고 설명했다.
그러나 예외적인 케이스가 존재한다고 했는데 특정 조건에 부합하면 부모 클래스의 이니셜라이저가 자동으로 상속된다.
(근데 사실 자식 클래스에서 이니셜라이저를 재정의하는 경우는 드물긴 함)
그래서 그 특정 조건이 무엇이냐 하면,
자식 클래스에서 프로퍼티 기본 값을 모두 제공한다고 가정할 때, 다음 규칙에 따라 이니셜라이저가 자동으로 상속된다.
- 규칙 1: 자식 클래스에서 별도의 지정 이니셜라이저를 구현하지 않는다면, 부모 클래스의 지정 이니셜라이저가 자동으로 상속된다.
- 규칙 2: 만약 규칙 1에 따라 자동으로 상속 받은 경우 또는 부모 클래스의 지정 이니셜라이저를 모두 재정의하여 부모 클래스와 동일한 지정 이니셜라이저를 모두 사용할 수 있는 상황이라면 부모 클래스의 편의 이니셜라이저가 모두 자동으로 상속된다.
자동 상속 예제 코드를 보자
class Person {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init(name: String) {
self.init(name: name, age: 10)
}
}
class Student: Person {
let major: String
override init(name: String, age: Int) {
self.major = "Computer Engineering"
super.init(name: name, age: age)
}
}
let student = Student(name: "Eden")
print(student.age) // 10
코드를 보면
- Student 클래스의 major 프로퍼티에 기본 값이 없더라도 이니셜라이저 안에서 적절히 초기화했고, 별도의 지정 이니셜라이저를 구현하지 않았기 때문에 규칙 1에 부합함으로서 부모 클래스의 지정 이니셜라이저가 자동 상속된다.
- 또한 부모 클래스의 지정 이니셜라이저를 모두 재정의했기 때문에 규칙 2에 따라 편의 이니셜라이저도 자동 상속되는 것을 확인할 수 있음
드디어 마지막..
요구 이니셜라이저(Required Initializer)
상속받을 때 반드시 재정의해야 하는 이니셜라이저이다. init 앞에 required 키워드를 붙여 사용한다.
자식 클래스에서 요구 이니셜라이저를 재정의할 때는 override 대신 required 수식어를 붙여야 함
다음은 사용 예제이다.
class Person {
let name: String
let age: Int
required init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class Student: Person {
let major: String = "Computer Engineering"
}
let student = Student(name: "Eden", age: 10)
부모 클래스에 요구 이니셜라이저를 구현해주었지만, 자식 클래스에는 요구 이니셜라이저를 구현하지 않았다.
이게 가능한 이유는 자식 클래스 저장 프로퍼티에 기본 값이 들어있고, 별다른 지정 이니셜라이저가 없기 때문에 이니셜라이저가 자동으로 상속되기 때문이다.
만약 자식 클래스에 새로운 지정 이니셜라이저를 구현한다면 부모 클래스로부터 이니셜라이저가 자동으로 상속되지 않으므로 요구 이니셜라이저를 구현해줘야 한다.
class Person {
let name: String
let age: Int
// 요구 이니셜라이저 정의
required init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class Student: Person {
let major: String
// 자신의 지정 이니셜라이저 구현
init(major: String) {
self.major = major
super.init(name: "Eden", age: 10)
}
required init(name: String, age: Int) {
self.major = "Computer Engineering"
super.init(name: "Eden", age: 10)
}
}
끝
'Study > Swift' 카테고리의 다른 글
[Swift] 고차함수(1) - map, flatMap, compactMap (0) | 2022.09.18 |
---|---|
[Swift] RunLoop.Mode (0) | 2022.08.01 |
[Swift] Run Loop (0) | 2022.07.25 |
[Swift] Initializer 심화 (1) (0) | 2022.07.19 |
[Swift] Property (0) | 2022.07.10 |