타입의 저장된 프로퍼티에 초기값을 설정하고 초기 설정을 수행한다.
초기화 (Initialization)는 인스턴스의 클래스, 구조체, 또는 열거형을 사용하기 위해 준비하는 단계이다. 이 단계에는 인스턴스의 저장된 프로퍼티에 초기값을 설정하고 새로운 인스턴스가 사용할 준비가 되기 전에 다른 설정이나 초기화를 수행하는 것을 포함한다.
특정 타입에 새로운 인스턴스를 생성하기 위해 특수 메서드를 호출하는 것처럼 초기화 구문 (initializers) 을 정의하여 초기화를 구현한다. Objective-C 초기화 구문과 달리 Swift 초기화 구문은 값을 반환하지 않는다. 초기화의 주요 역할은 처음 사용되기 전에 타입의 새로운 인스턴스가 올바르게 초기화되는 것을 보장하는 것이다.
클래스 타입의 인스턴스는 클래스의 인스턴스가 할당 해제되기 전에 정리를 수행하는 초기화 해제 (deinitializer) 도 구현할 수 있다.
클래스와 구조체는 해당 클래스 또는 구조체의 인스턴스가 생성될 때까지 모든 저장된 프로퍼티에 적절한 초기값을 반드시 설정해야 한다. 저장된 프로퍼티는 확정되지 않은 상태로 남아 있을 수 없다.
초기화 구문 내에서 저장된 프로퍼티에 초기값을 설정하거나 프로퍼티의 정의 부분으로 기본 프로퍼티 값을 할당할 수 있다.
Note
저장된 프로퍼티에 기본값을 할당하거나 초기화 구문 내에서 초기값을 설정할 때 해당 프로퍼티의 값은 모든 프로퍼티 관찰자 호출없이 직접 설정된다.
(willSet, didSet 호출이 이루어지지 않는다는 뜻인 듯 하다 ,,)
초기화 구문 (Initializers)은 특정 타입의 새로운 인스턴스를 생성하기 위해 호출된다. 가장 간단한 형식으로 초기화 구문은 init 키워드를 사용하여 작성하며 파라미터가 없는 인스턴스 메서드와 같다:
init() {
// perform some initialization here
}
아래의 예제는 화씨 눈금으로 표현된 온도를 저장하는 Fahrenheit 라는 새로운 구조체를 정의한다. Fahrenheit 구조체는 Double 타입의 temperature 라는 하나의 저장된 프로퍼티를 가지고 있다:
struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// Prints "The default temperature is 32.0° Fahrenheit"
이 구조체는 32.0 (물이 얼어버리는 화씨 온도)의 값으로 저장된 온도로 초기화되고 파라미터가 없는 init 의 단일 초기화 구문을 정의한다.
위에서 보았듯이 초기화 구문 내에서 저장된 프로퍼티에 초기값을 설정할 수 있다. 또는 프로퍼티의 선언의 일부로 기본 프로퍼티 값 (default property value) 을 지정할 수 있다. 프로퍼티가 정의될 때 프로퍼티에 초기값을 할당하는 것으로 기본 프로퍼티 값을 지정한다.
Note
프로퍼티가 항상 같은 초기값을 갖는다면 초기화 구문 내에서 값을 설정하기보다 기본값을 제공하는 것이 좋다. 결과는 같지만 기본값은 프로퍼티의 초기화를 선언에 더 가깝게 연결한다. 이것은 초기화 구문을 더 짧고, 명확하게 하고 기본값으로 부터 프로퍼티의 타입을 유추하게 할 수 있게 만든다. 기본값은 이 챕터 후반부에 설명하듯이 기본 초기화 구문과 초기화 구문 상속을 더 쉽게 활용할 수 있게 만든다.
프로퍼티가 선언될 때 temperature 에 기본값을 제공하여 더 간단한 형식으로 위의 Fahrenheit 구조체를 작성할 수 있다:
struct Fahrenheit {
var temperature = 32.0
}
입력 파라미터와 옵셔널 프로퍼티 타입이나 다음 섹션에서 설명하듯이 초기화 중에 상수 프로퍼티 할당으로 초기화 단계를 사용자화 할 수 있다.
초기화 단계를 사용자화 하는 값의 타입과 이름을 정의하기 위해 초기화 정의의 부분으로 초기화 파라미터 (initialization parameters) 를 제공할 수 있다. 초기화 파라미터는 함수와 메서드 파라미터로 동일한 기능과 구문을 가지고 있다.
다음 예제는 섭씨로 표현되는 온도를 저장하는 Celsius 라는 구조체를 정의한다. Celsius 구조체는 다른 온도 체계에서의 값으로 구조체의 새로운 인스턴스를 초기화하기 위해 init(fromFahrenheit:), 그리고 init(fromKelvin:) 2개의 초기화 구문을 구현한다:
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)
// freezingPointOfWater.temperatureInCelsius is 0.0
첫번째 초기화 구문은 인수 라벨 fromFahrenheit과 파라미터명 fahrenheit 의 하나의 초기화 파라미터를 가지고 있다. 두번째 초기화 구문은 인수 라벨 fromKelvin과 파라미터명 kelvin의 하나의 초기화 파라미터를 가지고 있다. 두 초기화 구문 모두 단일 인수를 섭씨 값으로 변환하고 temperatureInCelsius 라는 프로퍼티에 값을 저장한다.
함수, 메서드 파라미터와 마찬가지로 초기화 파라미터는 초기화 구문의 본문 내에서 사용하는 파라미터 명과 초기화 구문을 호출할 때 사용하는 인수 라벨 모두 가질 수 있다.
그러나 초기화 구문은 함수와 메서드 처럼 소괄호 앞에 식별 함수 이름을 가지지 않는다. 따라서 초기화 구문의 파라미터의 이름과 타입은 어떤 초기화 구문을 호출해야 하는지 식별하는 데 특히 중요한 역할을 한다. 이러한 이유 때문에 Swift는 제공하지 않으면 초기화 구문에서 모든 파라미터에 대해 자동적으로 인수 라벨을 제공한다.
다음 예제는 red, green, 그리고 blue 라는 3개의 프로퍼티 상수를 가지는 Color 라는 구조체를 정의한다. 이 프로퍼티는 색깔에서 빨간색, 초록색, 그리고 파란색을 나타내기 위해 0.0 에서 1.0 사이의 값을 저장한다.
Color 는 빨간색, 초록색, 그리고 파란색의 컴포넌트를 위해 Double 타입의 3개의 적절한 명칭의 파라미터를 가진 초기화 구문을 제공한다. Color 는 3개의 색깔 컴포넌트에 동일한 값을 제공할 때 사용하는 단일 white 파라미터를 가진 두번째 초기화 구문도 제공한다.
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
}
}
두 초기화 구문 모두 각 초기화 구문 파라미터에 값을 제공하여 새로운 Color 인스턴스를 생성할 수 있다:
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
인수 라벨을 사용하지 않고 초기화 구문을 호출할 수 없다. 인수 라벨은 정의 되었다면 항상 사용되어야 하고 생략 시 컴파일 시 에러가 발생한다:
let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - argument labels are required
초기화 구문 파라미터에 인수 라벨 사용을 원치 않을 경우 명시적으로 인수 라벨 대신에 언더바 (_)를 작성하여 기본 동작을 재정의한다.
다음은 섭씨 온도에 대한 Double 값으로 새로운 Celsius 인스턴스를 생성하기 위해 초기화 구문을 추가한 초기화 파라미터 (Initialization Parameters) 에서의 Celsius 예제의 확장된 버전이다:
struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius is 37.0
초기화 구문 호출 Celsius(37.0) 은 인수 라벨이 필요치 않다는 의도가 명확하다. 따라서 초기화 구문을 init(_ celsius: Double) 로 작성하여 이름 없는 Double 값을 제공하여 호출할 수 있다.
사용자 타입이 초기화 동안 값을 설정할 수 없거나 추후에 "값 없음"을 가질 수 있기 때문에 논리적으로 "값 없음"을 가질 수 있는 하나의 저장된 프로퍼티를 가지고 있다면 옵셔널 타입으로 프로퍼티를 선언한다. 옵셔널 타입 (optional type)의 프로퍼티는 자동적으로 초기화 동안 "아직 값 없음"을 가진다는 의도를 위해 nil 의 값으로 초기화된다.
다음의 예제는 response 라는 옵셔널 String 프로퍼티를 가지는 SurveyQuestion 이라는 클래스를 정의합니다:
class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// Prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
설문 질문 응답은 질문되기 전까지 알 수 없으므로 response 프로퍼티는 String? 타입 또는 "옵셔널 String" 타입으로 선언된다. 새로운 인스턴스 SurveyQuestion 이 초기화 될 때 "아직 문자열 없음" 이라는 의미의 기본값 nil 이 자동으로 할당된다.
초기화가 완료될 때까지 한정된 값으로 설정되는 한 초기화 중 언제든지 프로퍼티 상수에 값을 할당할 수 있다. 프로퍼티 상수에 값이 할당되면 더이상 수정할 수 없다.
Note
클래스 인스턴스의 경우 초기화 하는 동안 프로퍼티 상수를 수정하는 것은 해당 프로퍼티를 도입한 클래스에 의해서만 가능하다. 하위 클래스에서 수정할 수 없다.
SurveyQuestion 의 인스턴스가 생성되면 질문이 바뀌지 않는다는 것을 나타내기 위해 질문의 text 프로퍼티는 프로퍼티 변수보다 프로퍼티 상수로 사용하기 위해 위의 SurveyQuestion 예제를 수정할 수 있다. text 프로퍼티는 현재 상수이지만 여전히 클래스의 초기화 구문 내에서 설정할 수 있다:
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?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"