iOS - required init

이한솔·2023년 10월 10일
0

iOS 앱개발 🍏

목록 보기
23/49

MVVM 패턴으로 앱을 구현하면서 의존성 주입을 위해 init 생성자를 사용하려고 하는데 UIViewController의 하위 클래스에서 init(coder:) 필수 초기화 메서드를 구현해야 한다는 에러가 발생했다.


required init

필수 생성자로, 슈퍼 클래스에서 정의해둘 경우 서브 클래스가 슈퍼 클래스의 생성자를 상속받지 않는 한 서브클래스에서 반드시 구현해주어야 한다.
Swift의 안전성을 유지하고 이니셜라이저를 올바르게 사용하게 하기 위한 것이다.

예를 들어 Human 클래스 안에 required init을 구현해보자.

class Human {
    var name: String?
    
    required init(name: String) {
        self.name = name
    }
}

그러면 Human 클래스를 상속받는 Person이라는 서브클래스에서 required init메소드를 구현하지 않으면 에러가 발생한다.

class Person: Human {
    var nickName: String
    
    init(nickName: String) {
        self.nickName = nickName
        super.init(name: "")
    }
    
    //erorr! 'required' initializer 'init(name:)' must be provided by subclass of 'Human'
}


class Person: Human {
    var nickName: String
    
    init(nickName: String) {
        self.nickName = nickName
        super.init(name: "")
    }
    
    required init(name: String) {
        fatalError("init(name:) has not been implemented")
    }
}

overriding이지만 required init은 override 키워드 없이, 슈퍼 클래스와 동일한 형태로 구현을 해주어야 한다.

class Person: Human {
    var nickName: String?
}

이렇게 모든 프로퍼티가 기본 값을 갖고 있어 지정 생성자를 따로 작성하지 않으면 부모 클래스의 지정 생성자를 모두 상속받기때문에 required init을 쓰지 않아도 된다.
required init은 서브 클래스에서 지정 생성자를 직접 구현했을 경우에만 필수적이다.

💡 이유는?
부모의 모든 생성자를 상속받으면 부모에 선언되어 있는 required init(name:)을 상속 받지만, 자식 클래스에서 지정 생성자를 구현해버릴 경우, 더이상 상속 조건에 맞지 않아 required init(name:)을 상속받을 수 없어서 이땐 required init(name:)를 자식 클래스에서 필수로 정의 해줘야한다.



에러 발생 이유

UIView, UIViewController는 NSCoding 이라는 프로토콜을 채택하고있다.

💡 NSCoding이란?
storyboard나 xib으로 View를 그릴때 우리가 만들어둔 UI의 형태를 xml 형태로 저장한다. 저장한 것을 화면으로 가져오기 위해서 xml형태로 저장된 파일의 구성을 가져와야 하는데, 이 구성을 가져올 때 사용되는 것이 바로 init(coder: NSCoder)이다.
따라서 UIView나 UIViewController에서 storyboard나 xib를 통해 뷰를 생성할 때 지정생성자를 쓰려면 NSCoding 안에 필수로 선언되어있는 requred init을 써줘야하는 것이다.

class MainView: UIView {
    
    // 코드로 뷰를 생성할 때를 위한 지정 생성자
    init() {
        super.init(frame: .zero)
    }
    
    // 위 지정 생성자가 생김에 따라 부모 클래스 이니셜라이저 상속이 불가하여 구현해줘야하는 Interface Builder용 생성자
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

💡 required init의 내용이 fatalError인 이유는?
코드로 뷰를 그릴때는 xib, stroyboard로 그렸을 때만 불려야하는 이 생성자를 호출해서는 안되므로 호출 시 앱을 종료시킨다는 의미라고 생각하면 된다.
(fatalError에 대해서는 더 알아보자!)

    // 뷰를 코드로 그릴 때
    // 해당 이니셜라이저가 호출되는 것을 방지하고자 할 때 사용
    // 이 이니셜라이즈가 호출되면 앱이 강제로 종료된다.
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    // 뷰를 스토리보드나 xib파일로 그릴 때
    // 이 구현을 통해 슈퍼클래스의 초기화 코드가 실행되고 이니셜라이저를 호출한 상태에서 추가적인 설정이 가능하다.
    required init?(coder aDecoder: NSCoder) {
    super.init(coder: coder)
    }


참고: https://babbab2.tistory.com/171

0개의 댓글