Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

teunteun2

[Swift] required init?(coder: NSCoder) & override init(frame: CGRect) 본문

iOS

[Swift] required init?(coder: NSCoder) & override init(frame: CGRect)

teunteun2 2022. 4. 6. 17:25

 

UiView를 상속받아 Custom Class를 만들 때 우리는 생성자를 통해 뷰를 구성해야하기 때문에

required init?(coder: NSCoder) override init(frame: CGRect) 이 두 생성자를 만나게 되는데요,

오늘은 이 두 생성자의 차이점과 함께 코드로 뷰를 구성할 때 두 생성자를 모두 호출해야하는 이유에 대해서 정리해보았습니다

 

required init?(coder: NSCoder)

XIB는 XML Interface Builder의 약자로, Xcode 컴파일로는 번역할 수 없습니다

그래서 XIB를 nib으로 변경하여 Xcode 상에서 컴파일 할 수 있도록 만드는 과정이 필요한데요 ~

 

여기서 nib을 통해 컴파일하고 해체하는 과정을 unarchiving / deserialize 라고 하며

이 과정을 도와주는 것이 바로 NSCoder 라는 프로토콜이에요

 

결론적으로 Storyboard, XIB와 같은 인터페이스 빌더를 통한 뷰를 구성할 땐 NSCoder를 매개변수로 갖는 init? 생성자가 내부적으로 호출된답니다

 

UIViewController 구현부 : 내부적으로 호출되는 init?(coder: NSCoder) 생성자를 확인할 수 있다

 

근데 우리가 init?(coder: NSCoder) 생성자를 오버라이딩 할 때 앞에 required가 붙잖아요 ?

이건 NSCoding이 프로토콜로 정의되어 있고 NSCoding 내에 init? 생성자가 포함되어 있기 때문인데요,

프로토콜에서 언급된 프로토콜 초기화 함수는 반드시 구현해야하기 때문에 구현 시 앞에 required를 붙여주는 것입니다

 

이번엔 코드로만 뷰 혹은 셀을 구성할 경우를 볼까요?

 


override init(frame: CGRect)

override init(frmae:CGRect)는 XIB, Storyboard 와 같은 인터페이스 빌더를 사용하지 않고 코드로 뷰를 구성할 때 사용하는 생성자인데요, 코드로 뷰를 구성할 때 지정생성자 init(frame: CGRect)만 오버라이드 해서 뷰를 구성하면 된다고 생각이 들지만

!항상! required init?(coder:NSCoder)를 함께 호출해주어야 합니다. 안하면 에러가 나요 ..

 

왜그럴까요 ?

앞서 말햇듯 init?(coder:NSCoder)은NSCoding 프로토콜 내에 정의되어 있는 생성자이기 때문에

꼭 구현해야하기 때문이에요

 

Swift에선 자식클래스에서 지정 생성자를 작성하지 않으면, 부모클래스의 생성자를 자동으로 상속하기 때문에

인터페이스빌더를 통해 뷰를 생성해줄 땐 init이 없어도 UIView 내부에 있던 생성자가 상속되어 에러가 나지 않았던 겁니다!

UIView의 생성자

하지만 자식클래스에서 지정생성자를 작성하게 된다면 부모클래스의 생성자들이 더 이상 상속되지 않습니다

코드로 뷰를 구성할 땐 init(frame: CGRect)를 통해 프레임 초기화를 해야하기 때문에 우리는 지정생성자를 자식클래스에서 꼭 호출해야하죠 ? 그렇기 때문에 꼭 구현되어야 하는 init?(coder: NSCoder) 생성자가 자동 상속되지 않아 에러가 나는거랍니다

 

 

마지막으로 한가지 더 궁금한 것. 왜 init?(coder: NSCoder) 생성자는 옵셔널일까요 ?

NSCoding 프로토콜에 포함되어 있는 해당 생성자는 바로 실패 가능한 생성자이기 때문이에요, 

그래서 우리는 코드로 뷰를 짤 때 함께 명시해주어야 하는 required init?(coder:NSCoder) 생성자 내부에 

fatalError("init(coder:) has not been implemented")

위 문장과 같은 프린트 구문을 넣어줍니다


실패 가능한 이니셜라이저

생성자를 통해 뷰를 초기화 할 때, 이런저런 예외 상황 때문에 초기화를 실패할 경우가 생길 수도 있겠죠 ?

이럴 때 초기화 실패 가능성을 열어두기 위해 생성자가 초기화를 실패할 경우 nil을 반환하도록 만들어둘 수 있습니다.

 

하지만 생성자가 nil을 반환할 수 있게 된다면? 생성자 또한 옵셔널 타입이 되겠죠?

그래서 init?(coder:NSCoder)에 ?이 붙게 된 것입니다 : )

 

이렇게 실패 가능한 경우를 고려한 생성자를 실패 가능한 이니셜라이저 라고 부릅니다


 

다음에는 XIB로 커스텀 뷰 클래스를 만들 때 호출되는 awakeFromNib() 메서드와 생성자의 호출 시점에 대해 써보도록 할게요 ~ : )