ABOUT ME

Today
Yesterday
Total
  • init(frame:), init(nibName: , bundle:), NSCoding
    Apple🍎/iOS 2025. 2. 2. 19:49

    아래처럼 BaseViewController, BaseView를 만드는 도중, 둘의 init 이 서로 다른 형태인것을 보며 어디에 어떤걸 써야하는지 헷갈려서 작성하는 글이다..

    class BaseViewController: UIViewController {
        
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
            ...
        }
       
        init() {
            super.init(nibName: nil, bundle: nil) // XIB를 사용하지 않음
        }
        
        @available(*, unavailable)
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    class BaseView: UIView {
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            configureHierarchy()
            configureLayout()
            configureView()
        }
        
        @available(*, unavailable)
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func configureHierarchy() { }
        func configureLayout() { }
        func configureView() { }
    }
    

     

    위에서 작성한 것 중 이 3가지가 왜 쓰이는지 알아보자!

    // UIViewController
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
       super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
    
    // UIView
    override init(frame: CGRect) {
       super.init(frame: frame)
    }
    
    // 둘다 해당
    required init?(coder: NSCoder) {
       fatalError("init(coder:) has not been implemented")
    }
    

     

    UIViewController - init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)

    UIViewController의 경우, 특정 bundle을 기준으로 nib 파일을 입력하는 함수로 생성자를 갖는다.
    하지만 만약 코드로만 구현하는 경우, 초기화 할 nib 파일이 없기 때문에, 아래와 같이 두가지 방식으로 처리할 수 있다.

    // 1. super 함수로 처리
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        ...
    }
    
    // 2. xib를 사용하지 않는다고 명시
    init() {
        super.init(nibName: nil, bundle: nil) // XIB를 사용하지 않음
    }
    

     

    UIView - init(frame: CGRect)

    • 코드로 초기화: init(frame: CGRect)
    • 스토리보드(XIB)로 초기화: init(coder: NSCoder)

    init(frame)

    init(frame: CGRect)의 경우, 인터페이스 빌더가 아니고 코드로 UIView 오브젝트를 만들기 위해서 사용하는 생성자이다.
    UIView는 뷰의 초기 크기와 향후 슈퍼뷰를 기준으로 위치를 정해주어야하기에, frame을 기준으로 얼만큼 위치할 것인지에 대한 배치가 필수적이다.

    이제까지 UIView를 쓰면서 따로 호출하지 않았어도 디버깅하면 자동으로 init(frame:) 이 불리는 것을 확인할 수 있다. 상대적으로 우리가 슈퍼뷰를 기준으로 위치를 정해주고 있기에 초기값을 주지 않았어도 가능했던 것.

    init?(coder: NSCoder)

    둘다 Init?(coder:) 를 갖고 있는데
    실제로 스토리보드로 만들어진 객체는 init(coder: NSCoder)로 자동으로 호출하여 생성하기 때문에 필요없고,
    우리는 코드로 뷰를 생성할 때, coder 연결을 하지 않도록 아래와 같이 명시하는 것이다.

    required init?(coder: NSCoder) {
       fatalError("init(coder:) has not been implemented")
    }
    

     

    NSCoding, NSCoder

    그럼 NSCoder는 무엇일까?.. nib 파일과 무슨 상관인지?
    스토리보드 작업한 파일은 코드가 아니기 때문에, 컴파일러가 컴파일 타임에 인식할 수 없고 이를 코드로 변환해주는 과정이 필요하다.

    init(coder: NSCoder) 함수가 바로 그 역할을 해준다.
    NSCoder 타입의 객체로 파일을 초기화 시킨 후 컴파일 할 수 있게 디코딩 된 자기자신을 반환하는 작업을 한다.
    이렇게 내가 구성한 UIView의 상태를 앱의 disk에 저장하는 과정을 serialize, 그 반대로 disk에 저장된 상태를 불러오는 작업을 deserialize 라고 한다.
    *serialize(직렬화): 복잡한 객체의 연결구조와 내장된 자료를 간편하게 바이트처리 하는 것

    NSCoding 정의를 보면, 객체를 인코딩하고 디코딩하여 보관(archiving) 및 배포(distribution) 할 수 있도록 하는 프로토콜 이라고 작성되어 있다.
    그러므로 xib 파일을 serialize 시키기 위해 NSCoding의 init(coder: NSCoder) 가 필요하다고 생각하면 된다.

Designed by Tistory.