본문 바로가기
Xcode/Swift - PlayGround

PlayGround) Required Init()이 무엇일까?

by 후르륵짭짭 2021. 2. 9.
728x90
반응형

안녕하세요! 후르륵짭짭입니다.

정말 오랜만에 글을 쓰는 것 같습니다.

최근에 좋은 일이 있어서 기념 좀 했어서 블로그 운영이 조금 서툴렀습니다.

앞으로 다시 블로그를 꾸준히 적을 생각입니다!

이번에는 Swift를 좀 더 깊게 공부하면서 UIView에서 많이 볼수 있는 Required init()에 대해 알아 보려고 합니다.

 

** Required init()이란?? **

required init()은 무엇일까요???

말 그래도 필수적인 init() 이라고 생각하면 됩니다.

예시를 보도록 하겠습니다.

 

우리가 보통 클래스를 상속 받고 새로운 init()을 생성하기 위해서는 아래 처럼 override를 해줘야 합니다.

class J {
    var name : String
    
    init(){
        self.name = "ABC"
    }
}

class K : J{
    var major : String
    
    override init(){
        self.major = "DEF"
    }
    
}

하지만 이럴 경우에는 우리가 직접 override 해줄 부분을 찾아서 해줘야합니다...

만약 필수적으로 필요한 것이라면 반드시 알려줄 필요가 있겠죠?

그래서 생성자의 재정의를 필수적으로 해줘야 한다는 것을 알려주기 위해 있는 것이 required 입니다!!!

 

** 사용하는 방법 ** 

class A {
    var name : String
    
    required init(){
        self.name = "Unknown - name"
    }
}

class B : A {
    var major : String = "Unknown - major"
    
    init(input : String){
        self.major = input
        super.init()
    }
    
    //지정 init을 새롭게 생성 한다면 이렇게
    //required를 만들어줘야한다.
    required init(){
        self.major = "B class Required init start"
    }
}

//required init()을 실행시키면 super.init()이 없어도 해당 init()을 실행시켜준다.
let class_B : B = B()
print(class_B.name , class_B.major) // Unknown - name B class Required init start

let class_B2 : B = B(input: "major two")
print(class_B2.name , class_B2.major) // Unknown - name major two

이제 사용하는 방법에 대해 보도록 하겠습니다.

B 클래스는  A 클래스를 상속 받고 있습니다. 

그리고 A 클래스에 있는 init()을 반드시 재정의 해줘야한다고 할 때, required를 앞에 붙여주면 됩니다.

그러면 B클래스에서 다른 지정 생성자가 있다면 필수적으로 재정의 (Override) 해주라고 합니다.

그러면 위에 처럼 override init(){} 처럼 재정의를 해줄 수 있습니다!

 

하지만 상속 받는 클래스에서 지정 생성자가 없을 경우에는 자동으로 상속 받기 때문에 

아래 처럼 required init()이 있더라도 자동으로 생성이 됩니다.

class Person : NACoding{
    
    var name : String
    
    required init(){
        self.name = "Unknown - name"
    }
    
    required convenience init?(temp: String) {
        self.init()
        print(temp)
    }
    
}

class Student : Person{
    var major : String = "Unknown - Major"

}

//Required는 사용하면 상속 받는 클래스는 무조건으로 init()을 생성 해줘야합니다.
//하지만 상속받은 클래스에서 지정 init()이 없다면 자동 생성 해준다. 그래서 아래처럼 결과가 나온다.
let miJeong : Student = Student()
print(miJeong.major , miJeong.name) // Unknown - Major Unknown - name

 

** Override를 이용해서 required init()으로 변경하자 **

class C{
    
    var name : String
    
    init(){
        self.name = "Unkown C class - name"
    }
    
}


class D : C {
    var major : String = "Unkown D class - major"
    
    init(major : String){
        self.major = major
        super.init()
    }
    
    //이렇게 init()을 재정의 해주면서 required까지 붙일 수 있다.
    required override init(){
        self.major = "D class second Version - major"
        super.init()
    }
    
    //convenience은 init()이 필수로 필요하다.
    //이렇게 required를 사용해서 convenience를 만들 수도 있다.
    required convenience init(name : String){
        self.init()
        self.name = name
    }
}

class E : D {
    var grade : String
    
    init(grade : String){
        self.grade = grade
        super.init()
    }
    
    required convenience init(name: String) {
        self.init()
        self.name = name
    }
    
    //이미 부모 required에서 override를 내포하고 있다면 굳이 override를 적어줄 필요가 없다.
    required init() {
        self.grade = "F"
        super.init()
    }
    
}

let yagom : E = E()
print(yagom.grade) // F

let juHyun : E = E(name: "JuHyun")
print(juHyun.name) // JuHyun

위에서 보는 것 처럼 C 클래스에서 단순한 init()으로 되어 있는데 ,

D클래스에서 required override init()을 해줬습니다.

즉, 기존에 있던 init()을 override을 통해 다시 재정의 해주고 그것을 필수로 바꾸겠다는 것을 의미합니다.

그리고 D를 상속받은 E는 이미 required에 override의 의미가 들어 있기 때문에, 따로 override를 적지 않고

required init()을 해서 다시 재정의를 해줬습니다.

 

그리고 covenience도 동일한 초기화 생성자 이기 때문에 required로 override가 되기도 합니다!

(참고로 covenience를 사용하면 맨 위에 self.init()를 먼저 실행 시켜줘야합니다. covenience는 간편하게 사용하는 init()이기 때문에

기존의 지정 init()이 반드시 있어야하고 꼭 사용해줘야 합니다.)

 

** Protocol과 required **

우리가 일반적으로 UIView를 생성하고 Nib으로 생성자를 생성하면 매번 

이런 오류가 나오는데, 이것은 UiView가 NSCoding 프로토콜을 상속 받고 있기 때문 입니다.

이렇게 실패가능한 init?()을 가지고 있습니다.

따라서 위와 같이 required를 필요로 하는 겁니다.

protocol NACoding{
    
    init?(temp : String)
    
}

//Prototocal을 상속 받았는데
//그 때 init?()이 되어 있으면 required를 받게 된다.
class Person : NACoding{
    
    var name : String
    
    required init(){
        self.name = "Unknown - name"
    }
    
    required convenience init?(temp: String) {
        self.init()
        print(temp)
    }
    
}

class Student : Person{
    var major : String = "Unknown - Major"

}

let miDong : Person? = Person(temp: "테스트")
print(miDong!.name) // 테스트 \n Unknown - name

이렇게 init?(temp : String)을 required로 가지게 됩니다.

( 참고로 여기서 convenience를 가지게 된 것은 name의 초기값이 없기 때문에 지정생성자로 해줬기 때문 입니다. )

그러니깐 프로토콜에 실패가능한 생성자가 있고 그 프로토콜을 상속 받으면 위에 처럼 required를 필수로 가지게 됩니다!

 

참고 사이트 :

 - 실패가능한 init()을 가지는 프로토콜 - 

giraff-ios.tistory.com/1

 

required init?(coder:)

UIView와 UIViewController를 상속하여 지정이니셜라이저를 작성할 때, 다음과 같은 에러와 마주하게 된다. 'required' 이니셜라이저인 'init(corder:)'를 정의해주어야 한다는 에러인데, 다음과 같이 정의만

giraff-ios.tistory.com

 

- initializer requirement 'init(name:)' can only be satisfied by a required initializer in the definition of non-final class 'MyClass' 

stackoverflow.com/questions/26578664/how-to-satisfy-a-protocol-which-includes-an-initializer

 

How to satisfy a protocol which includes an initializer?

I defined a simple class: class MyClass { var name:String? required init() { println("init") } } I can add a new initializer in an extension like this: extension MyClass {

stackoverflow.com

 

728x90
반응형

댓글