Default Initializer가 Compiler에 의해 제공되는 경우

우선, default initializer가 제공되기 위해서는!
class 내부에 initializer가 구현되어 있지 않아야 한다.
또한, initializer를 구현하지 않기 위한 조건은 모든 저장 프로퍼티들이 초기화되어 있어야 한다.

class A {
    var num1 = 1
    var str: String? //nil로 초기화
}

위의 조건을 만족하였을 때, Compiler에 의해 Default initializer를 제공받게 되고,
Super Class의 모든(convienence, required, designated) initializer를 상속! 받게 된다.

class Person {
    var age: Int
    
    init(age: Int) {
        print("desinated")   
        self.age = age
    }
    
    required init() {
        print("required")
        self.age = 10
    }
    
    convenience init(stringAge: String) {
        print("convenience")        
        if let age = Int(stringAge) {
            self.init(age: age)
        }
        else {
            self.init(age: 10)
        }
    }
}

//subclass
class Student: Person {
    var school: String?
}

let s = Student()
//"required"
let s2 = Student(age: 10)
//"desinated"
let s3 = Student(stringAge: "100")
// "convenience"
// "designated"

 

Designated initializer를 오버라이드 하는 경우

우선! SubClass에서 designated initializer를 직접 구현하는 경우,
super class의 initializer를 상속받지 못한다!
convience의 경우에는 예외가 있긴 하지만, 우선은 없다고 생각하겠다.

superclass의 designated initializer를 오버라이드 하는 경우
해당 경우는 subClass에서 designated initializer를 가지게 된다.
따라서, 컴파일러에 의해 default initializer는 더 이상 제공되지 않기 때문에, 상속이 되지 않는다.

class Person {
    var age: Int
    
    init(age: Int) {
        print("desinated")
        self.age = age
    }
    
    init(someAge: Int){
        print("desinated default")
        self.age = someAge
    }
    
    required init() {
    	print("required")
        self.age = 10
    }
}

//subclass
class Student: Person {
    var school: String?
    
    init(age: Int, school: String) {
        self.school = school
        super.init(age: age)
    }
    
    required init() {
    	super.init()
    }
}

let s1 = Student(age: 10) // error
let s2 = Student(someAge: 100) // error

아까 말했듯이! initializer가 상속되지 않기 때문에!
sub class에서 required init()도 오버라이드 해주어야 한다.

let s1 = Student(age: 10) // error

해당 경우에는 subclass에서 init(age: shcool:) 로 오버라이드 되었기 때문에 사용이 불가능하다!

let s2 = Student(someAge: 10) // error

위의 경우에는 designated initializer가 구현이 되었기 때문에 superClass의 Initializer를 상속받지 못하기 때문에 에러가 난다.

하지만, Convenience의 경우에는 특수한 경우 사용이 가능한데, 이에 대해 살펴보자.

Convenience Initializer가 상속 가능한 경우

우선, Convenience Initializer는 오버라이드가 불가능하다.

하지만, 상속받을 수 있는 조건이 있는데,
첫번째로 말했듯이 default initializer가 compiler에 의해 제공되는 경우이다.

두번째로, subclass에서 superclass의 모든 designated(required를 포함한) initializer를
오버라이드 하게 되면 convenience initializer가 상속이 된다.

저번 포스팅에서 다뤘던, Convenience Initializer에 대해 다시 살펴보면,

  • self의 initializer를 호출해야 함
  • 최종적으로 designated의 initializer를 호출하여 모든 저장 프로퍼티의 초기화가 이루어져야 함


이제 자세히 살펴보자!

먼저 super class의 관계를 살펴보면
B는 A를 호출하고
A는 designated initialize를 호출한다.

이제, Sub class의 관계를 살펴보자 

subclass의 B는 상속되어 A를 호출하게 되는데, A 역시 상속되었기 때문에 문제가 되지 않는다. 

A에서는 self.init()을 통해 designated initializer를 호출하게 될텐데, 

designated initializer가 override 되었기 때문에, 이역시 문제가 되지 않는다. 

따라서, Convenicence Initializer는 최종적으로 designated initializer를 호출하게 되어
Convenience initializer의 2가지 조건을 만족하게 된다.

class Person {
    var age: Int
    
    init(age: Int) {
        print("desinated")
        self.age = age
    }
    
    init(){
        print("desinated default")
        self.age = 10
    }
    
    convenience init(someAge: Int) {
        print("convenience(someAge)")
        self.init(age: someAge)
    }
    
    convenience init(something: Int) {
        print("convenience(something)")
        self.init()
    }
}

//subclass
class Student: Person {
    var school: String?
    
    override init(age: Int) {
        super.init(age: age)
    }
    override init() {
        super.init()
    }
}

let s1 = Student(someAge: 10)
//"convenience(someAge)"
//"designated"
let s2 = Student(something: 20)
//"convenience(something)"
//"designated default"
복사했습니다!