[iOS] init(frame:), init(coder:)

Inwoo Hwang·2021년 8월 26일
1

iOS

목록 보기
9/13
post-thumbnail

iOS - init(frame:), init(coder:)


스토리보드 없이 앱을 만들다 보면 아래와 같은 override init(frame:)required init?(coder:) 이 필요한 것을 알 수 있다.

class OpenMarketListCollectionViewCell: UICollectionViewCell, CellDataUpdatable {
    static let identifier: String = "OpenMarketListCollectionViewCell"
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpUI()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

단순히 필요해서 썻었지 왜 필요한지는 제대로 알아보지 않은 것 같아서 공부한 내용을 정리해보자 글을 남겨봅니다.

init(frame: )은 뭐지?

일단 공식문서를 한번 보면

초기화를 하여 특정한 frame rectangle을 가진 새롭게 할당된 view 객체를 반환한다라고 적혀있습니다. 여기서 말하는 rectangle이 뭔가 궁금할 줄 알고 공식문서에서 바로 설명 해 주네요.

특정 뷰를 위한 frame rectangle을 얘기하는 것 같습니다. 그리고 frame에 대해서도 간략하게 설명하고 있네요(frame의 기점(origin)은 해당 뷰가 얹어져있는 부모뷰에 비례한다).

해당 이니셜라이저는 이 frame rectangle을 가지고 구현하고자 하는 뷰의 중심(center)와 경계선(bound)을 지정해 준다고 적혀있네요.

Discussion 부분을 조금 더 읽어보니까 해당 이니셜라이저를 왜 사용하는지 이해가 되었어요.

스토리보드, xib, nib과 같은 interface builder를 사용하지 않고 코드로 UIView class의 View object를 만들기 위해 지정된 이니셜라이저가 바로 이녀석인 것입니다.

그래서 코드로 작성하려는 label, button, indicator, view 등등 frame을 가진 모든 view 객체는 해당 이니셜라이저 속안에서 초기화가 되어야 하는겁니다!

*xib: XML Interface Builder

*nib: NeXT Interface Builder(빌드시 xib가 nib로 변환)

Init(coder: )는 뭐지?

해당 initializer 또한 먼저 공식문서를 살펴보자면...

주어진 압축해제 툴(여러 클래스 파일이 묶여있는 압축된 파일을 해제시켜주는 툴 이라고 이해했습니다.)로 부터 받은 데이터로부터 초기화된 객체를 반환한다...라고 이해했습니다만.. 설명이 굉장히 어렵네요.

unarchive란 뭐지?

기본적으로 storyboard나 xib를 활용하면 별도의 코딩 없이 앱의 속성을 수정할 수 있는데요. 이것을 가능하게 해주는 과정을 unarchiving이라고 합니다.

interface builder는 코드가 아니기 때문에 앱을 컴파일 하는 시점에서 컴파일러가 인식할 수 없고 이를 코드로 변환 해 주는 unarchiving 과정이 필요하다는 것이죠!

이 과정에서 init?(coder:)가 사용됩니다.

parameter coder를 통해 NSCoder 타입의 오브젝트가 전달되는 것입니다. 전달된 NSCoder 타입의 오브젝트가 decoding 되어 초기화된 후 컴파일 할 수 있게 decoding 된 자기자신(self)를 반환하는 작업이라고 보면 될 것 같습니다.

그래서 이게 왜 필요하냐구...

View의 UI를 초기화 해주는 다양한 과정:

  1. Storyboard with init(coder:)

내가 구성한 view의 상태를 앱의 disk에 저장하는 과정을 serialize라고 합니다. deserialize 는 반대로 disk에 저장된 상태를 불러오는 작업이라고 볼 수 있습니다. NSCoding이라는 프로토콜을 통해 이 serialize와 deserialize 작업이 가능해집니다.

Storyboard라는 interface builder를 사용하여 view의 상태를 수정할 경우 serialization 작업을 Xcode가 init(coder:)를 호출하여 앱 내 view 작업을 저장하고 불러오는 작업을 해줍니다.

  1. xib with awakeFromNib()

cell은 xib로도 많이 작성합니다. xib로 작성을 하게되면 awakeFromNib에서 초기화를 시켜주어야 합니다. 해당 메서드는 view.register(nib:, forCellWithReuseIdentifier:) 시점에서 불리게 됩니다.

  1. code with init(frame:)

init(frame:)을 코드로 작성하면 initialize를 cg rect bounds를 지정해 주는데 frame을 호출해서 초기화를 해줍니다. view.register(_:, forCellWithReuseIdentifier:)

init(coder:)이니셜라이저가 필요한 이유는 스토리보드를 통해 UI를 초기화하기 위해 필요합니다만 아이러니하게 storyboard를 사용할 때에는 해당 이니셜라이저를 선언할 필요가 없습니다만...코드로 UI작성을 할 때는 해당 이니셜라이저를 사용하지 않음에도 불구하고 view를 구현할 때 선언 해주어야 합니다.

왜그럴까요.

이 부분에 대해서는 의견이 분분합니다.

일단 모든 view는 NSCoding을 채택하고 있고 해당 init(coder:) required이기 때문에 storyboard를 사용하지 않음에도 무조건 선언해야 합니다.

그런데 storyboard를 사용하지 않음에도 선언해야 하는 이유는 정확한 이유는 모르겠습니다.

아무튼 코드로 작성을 하려면 이 두 이니셜라이저를 둘 다 상속 받아서 사용해야 합니다!

하나는 override, 다른 하나는 required인 이유는?

NSCoding 프로토콜은 이를 채택하는 클래스로 하여금, 위와 같이 실패가능한 이니셜라이저를 작성하도록 합니다. 해당 이니셜라이저는 지정 이니셜라이저입니다.

해당 프로토콜을 준수하는 클래스에서 프로토콜에서 요구하는 이니셜라이저 요구사항을 구현할 수 있습니다.

designated init 또는 convenience init으로말이죠.

두 경우 모두 "required"라는 modifier를 표시해야합니다.

출처: https://zeddios.tistory.com/256 [ZeddiOS]

프로토콜에 명시된 이니셜라이저를 구현하면 required 키워드가 붙여주어야합니다.

UIView와 UIViewController는 NSCoding 프로토콜을 구현하고 있으므로,

따라서 이를 상속받은 UICollectionViewCell과 같은 클래스에서는 스토리보드를 사용하지 않고있긴 하지만 init?(coder:)를 구현해줘야 하고 앞에 꼭 required를 붙여줘야합니다.

[참고]:

init(frame:) | Apple Developer Document

init(coder:) | Apple Developer Document

The Swift Programming Language - Initialization

[iOS - swift] init(frame:), required init?(coder aDecoder: NSCoder), prepareForInterfaceBuilder(), awakeFromNib() 초기화의 정체

[iOS] init?(coder:)란?

required가 붙은 이니셜라이저

[Swift]Initialization 정리 - 민소네

required init?(coder:) - 기린의 iOS

What exactly is init coder aDecoder?

[Swift ) Protocols (2) - ZeddiOS](

profile
james, the enthusiastic developer

0개의 댓글