https://bbiguduk.gitbook.io/swift/language-guide-1/initialization
여기들어가면 어마어마하ㄷ..분량이... 그만큼 초기화가 swift에서 중요하다.
Swift는 모든 저장된 프로퍼티가 초기값을 받을 수 있도록 클래스 타입에 대해 2가지의 초기화 구문을 정의한다.
=> 바로 지정된 초기화와 편의 초기화라는 친구들이다.
지정된 초기화(designated Initializer)
해당 클래스에 의해 도입된 모든 프로퍼티를 완벽하게 초기화하고 적절한 상위 클래스 초기화를 호출하여 상위클래스 체인까지 초기화 프로세스 진행한다.
편의초기화(Convenience initializers)
초기화 구문 파라미터를 기본값으로 설정하여 초기화구문을 돕는 보조초기화. 그림에서 보듯 이것은 수평으로 호출된다!
swift에서 클래스초기화는 2단계이다.
1단계 : 각 저장된 프로퍼티가 해당 프로퍼티를 도입한 클래스에 의해 초기값 할당된다.
즉 위 그림에서 맨아래있는 놈이 convenicence init을 통해 init을 할때 슈퍼클래스 한단계씩 클래스의 초기화를 호출하게 되고 맨위까지 가면 1단계 초기화가 끝나고 비로소 인스턴스의 메모리가 완전히 초기화되었다고 할 수 있다.
2단계: 어? 맨위까지 가서 인스턴스 메모리 초기화했어? 그러면 이제 그 후의 초기화가 가능해!뭐 예를들어 그 초기화해야하는 프로퍼티를 사용하거나 수정하거나 온갖 작업이 가능하단다. 뭐 self를 사용하건 인스턴스 프로퍼티를 읽건....즉 2단계에서는 부모 이상의 클래스의 저장 프로퍼티 값을 변경하는 것이 가능해진다.
이렇게 2단계초기화를 통해 부모의 초기화에 의해 자식에서 잘못덮어씌어지는 일을 막을수있다.
Swift Compiler가 에러없이 2단계초기화까지 되었는지 4가지 검사를 한다고 한다.
- 지정된 초기화 구문은 상위 클래스 초기화 구문에 위임되기 전에!! 클래스에 의해 먼저 내꺼다 초기화 되었는지 확인!
- 지정된 초기화 구문은 상속된 프로퍼티에 값을 할당하기 전 상위클래스 초기화 구문에 위임해야한다.
- 편의 초기화 구문은 모든프로퍼티에 값을 할당하기전 다른 초기화 구문에 위임해야한다
- 초기화구문은 1단계 초기화가 완료될때까지 인스턴스 메서드를 호출하거나 인스턴스 프로퍼티 값을 읽거나 self로 값 참조 X
자동 초기화 구문 상속 (Automatic Initializer Inheritance)
1. 하위클래스가 지정된 초기화 구문을 정의하지 않았어? 자동으로 상위 클래스 지정초기화 구문 상속한다.
2. 하위클래스가 규칙 1에 따라 상속하거나 정의의 부분으로 사용자 정의구현을 제공하여 모든 상위클래스 지정된 초기화구문의 구현을 제공하면 모든 상위 클래스 편의 초기화 구문을 자동으로 상속!
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
이렇게 Food를 상속받는 클래스가 있고 여기에는 초기화가 두가지방식이있다.
여기서 봐야할게 RecipeIngredient에 제공된 convenience init은 상위 클래스의 designated init과 같은 파라미터를 가지고 있다.
그래서 상위 클래스의 designated init을 재정의하기에 override붙여줘야함
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
이번엔 recipeIngredient를 상속받는 클래스를 한번더 만들어봤다.여기서 주목할것은 이미 프로퍼티에 값이 다있어서 init이 필요가 없다.이렇게되면 자동으로 상위 클래스에서 모두 지정된 초기화 구문과 편의 초기화구문을 상속받는다.
init?(실패가능한 초기화)
기존에는 컴파일 시점에 모든 프로퍼티가 초기화 되어있어야하기에 실패하면 바로 컴파일 에러가 뜬다고 위에서 말했다.
하지만 init뒤에 물음표 하나 붙이면 초기화에 실패하더라도 에러발생시키지않고 nil을 리턴한다. 그래서 실패가능한초기화로 생성할경우 무조건 인스턴스가 옵셔널 타입이라 옵셔널체이닝후 사용을 해야한다. 코드가 더러워질수도...?
class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class CartItem: Product {
let quantity: Int
init?(name: String, quantity: Int) {
if quantity < 1 { return nil }
self.quantity = quantity
super.init(name: name)
}
}
위의 코드와 같이 어떤 CarItem 초기화를 할때 quantity가 1 이하면 어? 나 생성안해~ 하면서 nil을 리턴하게 되는것이다.
'Swift' 카테고리의 다른 글
힙메모리 분석 - WWDC24 (1) | 2024.06.15 |
---|---|
매크로(Macros) (1) | 2024.03.07 |
Function(1급시민 , inout & 클로저✨) (0) | 2024.03.04 |
Assertions && Preconditions (0) | 2024.03.02 |
LLVM? Swift가 컴파일되는 과정 Swift 기초 (0) | 2024.03.01 |