Swift에서의 초기화
종류: designed init, convenience init (지정 초기화, 편의 초기화)
단계
- 모든 member 초기화 → 상속 받은 member 커스텀
지정 초기자
init(parameters) {
statements
}
클래스 내의 모든 프로퍼티를 초기화한다.
클래스마다 필수적으로 하나씩 가진다.
편의 초기자
convenience init(parameters) {
self.init() // ✅
statements
}
Optional 이다.
내부에 반드시 지정 초기자를 호출해야 한다. (위 코드의 self.init() 부분을 말한다.)
초기화 규칙
1. 모든 멤버의 초기화를 보장하자 !
- 지정 초기자 ⇒ 반드시 super class의 지정 초기자를 호출해야 한다. (= delegation)
- 편의 초기자 ⇒ 반드시 같은 class의 지정 초기자를 호출해야 한다. 모든 member의 초기화를 보장해야 하기 때문이다.
2. 상속에서의 초기화 규칙 == 컴파일을 강제한다 !
- 자신의 클래스 member들을 모두 초기화하고,
- super class로부터 상속 받은 member들을 super class의 지정 초기자를 호출함으로써 모두 초기화한다.
즉 super class의 지정 초기자 호출 전에 자신의 member들과 super class로부터 상속 받은 멤버들을 먼저 초기화 한다는 것이다.
- 이렇게 하지 않으면 super class의 값들로 덮어 씌워지게 되기 때문이다.
- 예시 (코드 출처 @seungchan2)
// MARK: - Initialization
init(frame: CGRect, mode: ButtonMode, text: String, fontSize: CGFloat) {
self.mode = mode
self.text = text
super.init(frame: frame) // ✅
setUI(text: text, fontSize: Int(fontSize))
setupMode(mode: mode)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError()
}
초기화 원리
모든 멤버들을 먼저 초기화 한 뒤, 커스텀 한다.
- 등산하고 하산하는 것과 같은 흐름이다.
1) 등산
- 클래스의 init 호출
- 클래스의 인스턴스들에게 메모리 주소를 할당
- sub class의 멤버들을 초기화 (= 지정 초기자 호출)
- super class의 멤버들을 초기화 (= 지정 초기자 호출)
- 이를 Root class까지 실행하며 모든 멤버들을 초기화한다.
2) 하산
- super class의 지정 초기자를 호출한 부분에서, 상속 받은 멤버들을 커스텀한다.
- 1번과 반대로 Root class로부터 시작해서 sub class까지 실행한다.
초기화 자동 상속
모든 member들을 초기화해야 하므로 생기는 제약사항을 말한다.
- 모든 신규 멤버들에 default 값이 있으면 자동 상속된다.
- sub class가 편의 초기자를 하나도 정의하지 않았다면 자동 상속된다. (하나라도 존재한다면 super class의 init을 전부 상속할 수는 없다.)
- super class의 지정 초기자를 모두 상속 받거나 작성하게 되면, 편의 초기자도 자동으로 상속된다.
required init
required 키워드를 초기자 앞에 붙이면, 모든 sub class들이 명시적으로 해당 초기화를 구현한다.
- 이미 상속의 의미가 존재하므로 override는 붙여주지 않는다.
정리 (예시 코드)
표시해놓은 시간 태그 부분을 커스텀 뷰로 만들면서 전부 사용했다.
import UIKit
import SnapKit
import Then
final class TimeView: BaseView {
// MARK: - Properties
let timeLabel = UILabel().then {
$0.font = UIFont.font(.pretendardMedium, ofSize: 18)
$0.textColor = Color.gray800
}
// MARK: - Initialization
convenience init(time: String) {
self.init(frame: .zero) // ✅ 같은 클래스의 지정 초기자를 호출
self.timeLabel.text = time
updateUI()
}
override init(frame: CGRect) {
super.init(frame: frame) // ✅ super class의 지정 초기자를 호출
}
@available(*, unavailable)
required init?(coder: NSCoder) {
/*
✅ 모든 sub class들에 명시적으로 지정 초기자 구현
super class의 초기자를 자동으로 상속받도록 하기 위함
*/
fatalError()
}
// MARK: - Functions
override func setupView() {
super.setupView()
backgroundColor = Color.white
makeRoundedWithBorder(radius: 6, color: Color.darkMint.cgColor)
addSubview(timeLabel)
}
override func setupConstraints() {
super.setupConstraints()
timeLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(6)
make.leading.equalToSuperview().offset(10)
make.trailing.equalToSuperview().offset(-10)
}
}
private func updateUI() {
let viewSize = timeLabel.intrinsicContentSize
let width = viewSize.width + 10
let height = viewSize.height + 6
frame.size = CGSize(width: width, height: height)
timeLabel.center = CGPoint(x: width / 2, y: height / 2)
}
}
참고
[iOS - swift] Designated init, Convenience init, 초기화의 핵심, 초기화 상속
required init?(coder:)란 무엇인가?
'개발 > iOS' 카테고리의 다른 글
[iOS] MVC 삽질기, 클린아키텍처와 MVVM (0) | 2022.09.03 |
---|---|
[iOS] TabBarItem으로 들어간 이미지가 제대로 표시되지 않을 때 (0) | 2022.04.24 |
[iOS] 서브뷰와 addSubView (0) | 2022.04.14 |
[iOS] Carousel 구현 아이디어 (0) | 2022.03.24 |
[iOS] IQKeyboardManager (0) | 2022.03.24 |
댓글