초기화는 클래스, 구조체, 열거형 인스턴스를 사용 준비하는 단계로 각 프로퍼티의 초기 값을 설정한다.
이전에는 단순히 선언과 함께 초기화를 해주면서 init 코드를 보면 좀 두려움이 있었던 것 같은데,
규칙이나 순서가 몇가지 있다는 것을 이해하는 좋은 시간이었다.
class SomeClass {
init() {
}
}
프로퍼티 선언과 동시에 값을 지정해 초기값으로 사용하고 init에서 지정하지 않을 수 있습니다.
struct SomeStruct {
var someProperty = 32.0
//구현하지 않아도 됨
init(property: Double) {
self.someProperty = property
}
}
초기화 인자값 및 할당을 커스터마이징 할 수 있다.
struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
프로퍼티가 옵셔널 타입이라면 init과정에서 별도로 값을 할당하지 않는다면 자동적으로 nil이 할당되어있다.
var optionalValue: Int? = nil //요거 할 필요 없다는 얘기
초기화 중에 상수 프로퍼티에 값을 할당 할 수 있다.
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// Prints "How about beets?"
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
이니셜라이저에서 다른 이니셜라이저를 호출한다.
값을 바로 할당해 초기화 하는 것.
아래와 같이 쓸 수 있다.
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
//아래의 self.init은 origin과 size의 할당을 위임한다는 의미
//말이 어려워서 그렇지만... 그냥 다른 init 호출해서 쓰는게 가능하다는 걸로 이해
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
Class에는 상속이란게 있어서 Super Class 와의 관계가 생기면서 좀 복잡해지는 것 같다.
이제부터 init의 규칙? 같은 내용이다. 지루하지만 한번 이해하고 알아두면 좋은듯 하다.
모든 클래스의 프로퍼티와 슈퍼클래스의 모든 프로퍼티는 초기에 값이 설정되어야하며, 2가지 방법을 제공한다. (Class 내의 init끼리의 규칙)
//Designated Initializer
init(params) {
//초기화
}
//Convenience Initializer
convenience init(params) {
//초기화
}
그림은 복잡하지만 글이 이해가 됐다면 쉽게 보인다.
단계 1
단계 2
swift 는 위 2가지 과정을 안전하게 사용하도록 4가지의 규칙을 제공. 규칙을 지키지 않으면 컴파일 에러
안전하고 특정한 상황에서 오버라이드가 가능한데 아래의 예시에서 가능하다.
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
//정의 시점에 모든 프로퍼티가 할당될 값이 지정된다면 자동 initializer가 생성된다.
}
class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
let bicycle = Bicycle()
Propagation of Initialization Failure
init? 과 같이 구현을 하면 실패가능한 초기자가되어 nil을 리턴할 수 있게된다.
Overriding a Failable Initializer
실패가능한 초기자를 override 하여 실패 불가능한 초기자로 가능
class Document {
var name: String?
// this initializer creates a document with a nil name value
init() {}
// this initializer creates a document with a nonempty name value
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class AutomaticallyNamedDocument: Document {
override init() {
super.init()
self.name = "[Untitled]"
}
override init(name: String) {
super.init()
if name.isEmpty {
self.name = "[Untitled]"
} else {
self.name = name
}
}
}
init!
실패가능한 초기자를 강제 언래핑해 오버라이드도 가능
```
class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
```
모든 서브클래스에서 반드시 구현해야 하는 초기자에는 아래와 같이 required 키워드를 붙여 구현 가능.
```
class SomeClass {
required init() {
// initializer implementation goes here
}
}
```
#학습에 대한 내용으로 틀린 내용이 있을 수 있습니다.
#댓글로 남겨주시면 더 좋은 게시글로 수정하도록 하겠습니다.