클래스, 구조체, 열거형의 인스턴스를 사용하기 위해 준비하는 것.
인스턴스의 저장 프로퍼티 초기값을 정할 수 있다.
구조체나 클래스의 인스턴스가 생성될 때 저장 프로퍼티의 값이 다 초기화되어야 함!
요 프로퍼티들은 선언할 때 초기화될 수도 있고, 이니셜라이저로 초기화될 수도 있음.
이니셜라이저는 특정 타입의 새로운 인스턴스를 생성하기 위해 호출됨!
제일 기본적인 형식은 매개변수가 없는 형식인데,
init() {
// perform some initialization here
}
실제 구조체에 적용해 보면,
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"
요런식으로 init
에서 구조체의 저장 프로퍼티의 값을 설정해줄 수 있다.
당연히 원래 하던 대로 구조체 안에서 프로퍼티 선언하면서 값 설정해줘도 됨.
struct Fahrenheit {
var temperature = 32.0
}
요런식으루.
initializer 정의에 매개변수를 넣을 수 있음!
메소드 매개변수처럼 고대~~로 쓰면 된당.
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
이런식으로 구조체 Celcius
의 인스턴스를 만들 때 매개변수로 전달해주는 인자에 따라서 호출되는 init이 달라짐!
함수나 메소드처럼 매개변수 이름이랑 우리가 호출할 때 쓰는 label을 설정할 수 있다.
근데 init은 함수 이름이 없기 때문에 요 매개변수 이름으로 구분해야 하기에 상당히 중요함!
그래서 argument label을 설정하지 않으면 Swift가 알아서 정해준당.
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
구조체는 red, green, blue의 색깔 배율을 0.0~1.0까지 조절하는데, white로 설정하면 배율이 다 같아져서 흰색 계열이 나올 수 있도록 한다.
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
요런식으로 매개변수 이름을 그대로 써서 호출하면 된다. argument label을 굳이 설정하지 않아도 됨!
let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - argument labels are required
이런식으로 매개변수 이름을 안써주면 안됨!!!!!
매개변수 이름을 안 써주고 싶다면?
_ 요걸 써주면 된다. underscore이라고 하는데, 함수 할때 했던듯?
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
이런식으로 써먹을 수 있삼.
만들어놓은 구조체, 클래스, 열거형의 저장 프로퍼티에 값이 없어도 된다고 하려면 옵셔널을 추가하면 됨!
그러면 자동으로 nil로 초기화되고, 인스턴스 만들 때 굳이 초기화 안 해줘도 됨.
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."
요런식으로 클래스 인스턴스 만들 때 옵셔널이 아닌 text만 초기화해주고, response는 나중에 값을 넣어줘도 된다.
상수 프로퍼티도 만들어서 초기화할 수 있음!
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.)"
let으로 선언하면 요 선언 뒤에는 더이상 바뀌지 않지만, 초기화할 때는 바꿔줄 수 있다.
간단함! 뭔가 굳이 초기화하지 않아도 될 때, default initializer가 자동으로 생성되고 실행되는 거임.
예제를 보면 바로 이해된다.
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
이런식으로 ShoppingListItem
클래스의 모든 요소가 이미 초기화가 되어 있거나 옵셔널로 선언돼 있어서 굳~~~이 이니셜라이저가 쓰일 필요가 없을 때, default initializer가 생성돼서 매개변수 없이 인스턴스를 생성할 때 실행된다.
구조체의 멤버별 이니셜라이저도 있음!
이것도 자동으로 생성되는 건데, 이니셜라이저를 따로 만들어주지 않았을 경우에 생성됨.
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
let zeroByTwo = Size(height: 2.0)
print(zeroByTwo.width, zeroByTwo.height)
// Prints "0.0 2.0"
let zeroByZero = Size()
print(zeroByZero.width, zeroByZero.height)
// Prints "0.0 0.0"
요런식으로 초기값을 갖고 있는 구조체의 인스턴스를 만들 때, 각 프로퍼티마다 값을 또 설정해줄 수 있음.
요기 쓰이는 이니셜라이저도 자동 생성되는 거라구~!
Default Initializer
는Custom Initializer
를 만들어두지 않았을 때만 자동으로 생성되고, 만약 하나라도 init을 선언했다면 생성이 안됨!
근데 Default Initializer도 쓰고, Custom Initializer도 쓰고 싶다면?
Extension
을 사용해서 거기에다 Custom Initializer를 써주면 됨!
다른 이니셜라이저를 호출해서 사용할 수도 있다. 코드 재사용을 막아준다는 장점이 있는데, 요걸
Initializer Delegation
이라고 함!
이 delegation은 두 타입에 따라 다르게 적용됨!
일단 값 타입부터 살펴보면,
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: Point(x: originX, y: originY), size: size)
}
}
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
요런식으로 기본 이니셜라이저를 쓸 수도 있고,
Point
, Size
구조체를 이니셜라이저의 매개변수로 전달해서 얘네들의 이니셜라이저를 호출할 수도 있음!
구조체같은 값 타입들은 이렇게 self를 사용해 자기 자신의 이니셜라이저를 재사용할 수 있다.