[iOS] CustomView init

Minsang Kang·2023년 9월 22일
0

iOS Basic

목록 보기
2/3
post-thumbnail

UIKit에서 UI를 구현하는 방법 중 크게 두 가지 방법으로
Storyboard를 통해 UI를 구현하는 방법과
코드로 UI를 구현하는 방법이 있죠!

그중 CustomView를 만들때는 대부분 코드로 UI를 만들어왔었습니다.

근데 문득 오랜만에 CustomView를 만드려다보니 init을 어떻게했더라?
override init인가 convenience init인가, required init도 있었던 것 같은데...?

라는 상황이 몇번 발생하더라구요...😅

그래서 이번 기회에 한번 init과 관련하여 정리를 해볼까 합니다!

init

먼저 class의 경우 프로퍼티가 있는 경우 Designated init을 통해 모든 프로퍼티를 초기화해야만 합니다.
흔히 init 으로 작성하는것이 바로 Designated init 이랍니다.

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

그러면 만약 상속관계가 있는 경우 super.init은 어떻게 사용되어야 할까요?

super.init

상위 클래스를 상속받은 하위 클래스에서 init하는 경우 하위 클래스의 내부 property를 모두 초기화를 한 후에 super.init을 호출해야 합니다!
그렇게 해야만 비로소 self.으로 프로퍼티나 메소드 사용이 가능하답니다!

class Man: Person {
    var isHandsome: Bool
    
    init(name: String, age: Int, isHandsome: Bool) {
        self.isHandsome = isHandsome
        super.init(name: name, age: age)
    }
}

이런식으로 상속받은 하위 클래스의 경우 먼저 초기화를 한 후에 super.init을 호출하면 된답니다.

그러면 convenience init은 뭘까요?

convenience init

convenience init은 보조 이니셜라이저 입니다.
여기서 보조라는 것은 Designated init을 보조하는 이니셜라이저라는 뜻입니다.
그러면 보조한다는 것은 뭘 뜻하는 걸까요?

바로 convenience init을 사용하여 Designated init을 호출하는 용도로 사용되는 보조 이니셜라이저 라는 뜻입니다.

즉, convenience init 내부에서 self.init 함수를 호출해야 한다는 것이 중요합니다!

class Man: Person {
    var isHandsome: Bool
    
    init(name: String, age: Int, isHandsome: Bool) {
        self.isHandsome = isHandsome
        super.init(name: name, age: age)
    }
    
    convenience override init(name: String, age: Int) {
        self.init(name: name, age: age, isHandsome: true)
    }
}

이런식으로 사용이 가능하답니다. 간단하게 한 프로퍼티의 기본값을 설정하는 식으로 해봤어요

그러면 override initinit이랑 어떤점이 차이가 있을까요?

override, overloading

override init 을 알아보기 이전에, 먼저 override, overloading 기억 나실까요?

overloading같은 메소드명이지만 파라미터가 다르거나 반환타입이 다른 메소드 입니다!
override같은 메소드명에 파라미터와 반환타입도 모두 같은 메소드 입니다.
즉, 기존의 메소드 기능을 재정의할 때 사용되죠!

그러면, 상위 클래스를 상속 받는 클래스 내에서 init을 사용할때는...?

class Person {
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

상위 클래스의 init 부분과

class Man: Person {
    var isHandsome: Bool
    
    init(name: String, age: Int, isHandsome: Bool) {
        self.isHandsome = isHandsome
        super.init(name: name, age: age)
    }
}

하위 클래스의 init을 살펴보면
같은 init 메소드명에 다른 파라미터였다는 사실!
따라서 overloading init을 사용하고 있었던것이였습니다!

ㅇㅋㅇㅋ 그러면 override init은 어떤걸까요?

override init

override가 되려면 메소드명도, 파라미터도, 반환값도 모두 같아야 한다고 했죠?
즉, init 앞에 override가 붙여지는 경우는 상위 클래스의 init과 동일한 파라미터로 사용될 때 입니다!

예상대로 상위 클래스의 init과 파라미터가 동일한 경우는 override 키워드를 꼭 붙여야 한답니다!

좋아좋아 그러면 이제 마지막으로, required init도 알아볼께요!

required init

required의 의미는 필수적으로 init이 필요하다! 라고 명시하기 위한 키워드 입니다.

사진처럼 상속받는 클래스내에서 꼭 구현해줘야 하는 init이 필요한 경우 나타내는 키워드 라고 생각하면 될 것 같아요!
이게 필요한 상황을 좀만 더 생각해보면

아까 위에서 동일한 파라미터 조합의 init인 경우 override가 명시되어야 했잖아요?
이럴 경우 상위 init의 파라미터 조합에 따라서 override를 명시해야 할수도, 안할수도 있는 상황이죠!
그리고 다른 파라미터 조합으로 init을 하면 override 없이도 가능하죠!

따라서 하위 클래스에서 꼭 구현해줘! 라고 reqired 키워드로 명시하면 이를 채택하는 하위 클래스에서는 override를 고민할 필요 없이 required init을 구현해야만 하는 상황이 되는겁니다!

여기까지 이해가 되셨으면 이제 마지막으로 CustomView의 상위 클래스인 UIView의 init을 알아봅시다!

UIView init

CustomView를 생성하기 위해서는 UIView 또는 그 하위클래스를 채택해서 구현합니다
따라서 UIView의 init이 곧 CustomView의 상위 클래스의 init이라는 것이죠!

그러면 UIView의 init은 어떤형태가 있을까요?

바로 frame값을 파라미터로 받는 init과 coder값을 파라미터로 받는 init이 존재한답니다.
두가지는 용도에 따라 나뉘면서, 필수로 작성해야 하는 생성자랍니다.

init(frame: CGRect)

먼저 init(frame: CGRect)의 경우는 코드로 View를 만들 때 호출되는 init 입니다.
보통 CustomView를 코드로 만드니 저희가 주로 사용하게 되는 init인거죠!

init(coder: NSCoder)

그리고 init(coder: NSCode)의 경우는 Storyboard 또는 Xib으로 View를 만들 때 호출되는 init 입니다.

그러면 이제 퍼즐들이 좀 맞춰질까요!!

CustomView init

자 정리를 해보죠. CustomView를 코드로 만들기 위해서는
1. UIView를 상속받아야 한다.
2. 코드로 생성하기에 UIView의 init(frame: CGRect) 호출이 필요하다.
-> 따라서 override 키워드를 사용해서 customView 내에서 호출이 필요하다는 점!
3. init(coder: NSCoder) 또한 필수로 호출해야 한다.
-> 따라서 required 키워드가 붙여지는 것이였죠!

그리고 추가적으로 사용하기 편하게 하기 위한 convenience init까지 고려해보면
4. convenience init을 통해 받은 파라미터 값들로 customView 내 프로퍼티 값들을 모두 초기화시켜야 합니다.
5. 그리고 꼭 self.init을 호출해야 합니다!

이제서야 머리속에 뒤엉켰던 init들이 좀 잡힌 것 같네요...ㅎㅎ😄

CustomView 생성

최종적으로 간단한 CustomView 코드로 마무리할께요!

import UIKit

class BlackLabel: UILabel {
    /// 코드로 View를 생성시 불리는 필수 생성자, override 키워드로 재정의 필요
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    /// Storyboard 또는 Xib으로 생성시 불리는 필수 생성자, required 키워드를 그대로 명시
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    /// 사용하기 편리하게 필요한 값들을 파라미터로 받을 수 있는 생성자
    convenience init(text: String) {
        self.init(frame: .zero)
        self.configure(text: text)
    }
    
    /// customView 관련 초기화작업 부분
    private func configure(text: String) {
        self.translatesAutoresizingMaskIntoConstraints = false
        self.textColor = .black
        self.text = text
    }
}

이런식으로 간단하게 검은색 Label을 만들어봤어요!
그러면 ViewController 내부에서 이렇게 사용이 가능하답니다!

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let blackLabel = BlackLabel(text: "Hello World!")
        self.view.addSubview(blackLabel)
        NSLayoutConstraint.activate([
            blackLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            blackLabel.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
        ])
    }
}

profile
 iOS Developer

0개의 댓글