초기화(initialization)는 클래스, 구조체, 열거형의 인스턴스를 준비하는 과정(process)이다.
인스턴스의 '저장 프로퍼티에 대한 초깃값을 설정'하는 것과 새로운 인스턴스를 사용하기 전에 '필요한 다른 어떤 설정 또는 초기화'를 포함한다.
이 초기화 과정은 초기자(initializers)를 정의함으로써 구현할 수 있다.
초기자(initializers)
특정 유형의 새 인스턴스를 생성하기 위해 호출할 수 있는 특수한 메서드init() { // perform some initialization here }
Objective-C의 초기자와 달리 Swift의 초기자는 값을 반환하지 않는다.
초기자의 주요 역할은 새로운 타입의 인스턴스가 처음 사용되기 전에 올바르게 초기화 되도록 하는 것이다.
클래스 또는 구조체의 인스턴스가 생성되기 전까지 모든 저장 프로퍼티는 적절한 초깃값으로 설정되어 있어야 한다. 저장 프로퍼티는 불확실한 상태로 둘 수 없다.
저장 프로퍼티의 초기값은 '초기자(initializers)'안에서 설정하거나 프로퍼티를 정의할 때 '기본 프로퍼티 값'으로 할당하는 것으로 설정할 수 있다.
저장 프로퍼티의 초깃값을 '기본 프로퍼티 값'으로 설정하거나 '초기자'로 설정할 경우 프로퍼티 옵저버를 호출하지 않는다.
struct Adult {
var age: Int
init() {
age = 20
}
}
let a = Adult()
a.age // 20
struct Adult {
var age = 20
}
프로퍼티가 항상 똑같은 초깃값을 가진다면 '기본 프로퍼티 값'으로 초깃값을 설정한다.
최종 결과는 같지만 초기자를 더 짧고 명확하게 해주고 '기본 초기자(default initializer)'와 '초기자 상속(initializer inheritance)'을 더 쉽게 활용할 수 있다.
'입력 매개변수' 및 '옵셔널 프로퍼티'를 사용하거나 초기화 중에 '상수(constant) 프로퍼티를 할당'해 초기화를 사용자 정의할 수 있다.
초기화 과정을 사용자 정의하는 값의 타입과 이름을 정의하기 위해 '초기화 매개변수'를 제공할 수 있다. 초기화 매개변수는 함수 및 메서드 매개변수와 동일한 기능과 구문(syntax)을 갖는다.
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 // 100.00
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
freezingPointOfWater.temperatureInCelsius // 0.0
초기화 매개변수는 초기자 본문에서 사용할 '매개변수 이름'과 초기자를 호출할 때 사용할 '인자 라벨'을 모두 가질 수 있다.
초기자는 식별용 함수 이름을 가지지 않기 때문에 초기자 매개변수의 이름과 타입은 초기자를 식별하는데 중요한 역할을 담담한다.
struct Color {
let red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
초기화 매개변수에 인자 라벨을 사용하고 싶지 않다면 해당 매개변수에 명시적 인자 라벨 대신 '밑줄(underscore; _ )'을 작성해 기본 동작을 재정의한다.
struct Celsius {
var temperatureInCelsius: Double
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0)
bodyTemperature.temperatureInCelsius // 37.0
저장 프로퍼티가 논리적으로 '값 없음'을 허용하는 속성을 가질 경우 옵셔널 타입으로 선언한다.
class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
}
상수 프로퍼티의 값은 초기화 중 언제든지 할당할 수 있다. 상수 프로퍼티에 한 번 값을 설정한 뒤에는 더 이상 수정할 수 없다.
클래스 인스턴스에서 상수 프로퍼티는 해당 프로퍼티를 도입한 클래스에서만 수정할 수 있다. 하위 클래스에서는 수정할 수 없다.
class SurveyQuestion {
let text: String
init(text: String) {
self.text = text
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.text = "How about cheese?" // Error
모든 프로퍼티에 '기본값'을 제공하면서 자체적으로 초기자를 제공하지 않는 클래스 또는 구조체는 '기본 초기자(default initializers)'를 제공받는다.
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
구조체 타입은 자신만의 초기자를 정의하지 않아도 '멤버 초기자(memberwise initializer)'를 자동으로 부여받는다.
구조체는 기본값이 없는 저장 프로퍼티를 가지고 있는 경우에도 멤버 초기자를 부여받는다.
struct Person { var name: String var age: Int } let p = Person(name: String, age: Int) let p = Person(name: String) // ERROR
'멤버 초기자'를 호출할 때, 기본 값을 가진 프로퍼티가 있다면 해당 속성의 값을 생략할 수 있다.
struct Size { var width = 0.0, height = 0.0 } let twoByTwo = Size(width: 2.0, height: 2.0) // width, height 모두 2.0 let twoByTwo = Size(width: 2.0) // width = 2.0, height = 0.0 let twoByTwo = Size() // width, height 모두 0.0
cf.
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
https://xho95.github.io/xcode/swift/grammar/initialization/2016/01/23/Initialization.html