개발자의 삽질
[Swift] Initialization - 1편 본문
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
이번엔 Initialization에 대해 알아보자
Initialization은 class, structure, enumeration 인스턴스를 사용하기 위한 준비 단계이다. 이 과정에서는 stored 프로퍼티를 위한 초기 세팅 과정을 진행하고 새 인스턴스를 사용가능하게 만들기 위해서 필요한 추가적인 초기화 단계를 수행한다.
Objective-C의 생성자와는 다르게 Swift에서는 값을 반환하지 않는다.
Setting Initial Values for Stored Properties
클래스와 구조체를 생성할 때, 반드시 모든 저장 프로퍼티가 적절한 초기값으로 설정되어야 한다.
한가지 알아두어야 할 점은, 기본값을 설정할 때나, 생성자를 이용해 초기값을 설정할 때는, 프로퍼티 옵저버가 호출되지 않는다.
Initializers
특정 타입의 새로운 인스턴스를 생성하기 위해서 생성자가 호출된다. init 키워드를 사용한다.
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"
Default Preperty Values
저장 프로퍼티에 생성자를 이용해서 초기값을 세팅할 수도 있지만, 프로퍼티를 정의할 때 바로 세팅할 수도 있다.
struct Fahrenheit {
var temperature = 32.0
}
Customizing Initialization
Initialization Parameters
생성자에 생성자 파라미터를 제공할 수도 있다.
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
2개의 생성자 모두 하나의 파라미터를 받고 있다.
Parameter Names and Argument Labels
함수와 메서드 파라미터와 같이, 생성자 파라미터 또한 파라미터 이름과 라벨을 제공해 줄 수 있다. 그러나 생성자 그 자체는 이름을 가질 수 없기 때문에, 생성자 파라미터의 타입과 이름이 중요하다. 따라서 생성자 파라미터에 변수 라벨이 없다면 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
}
}
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)
// 컴파일 에러 발생! - 변수 라벨이 있어야 한다!!
Initializer Parameters Without Argument Lables
변수 라벨을 사용하고 싶지 않다면 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
Optional Property Types
저장 프로퍼티가 값이 없을 수도 있을 경우에는 옵셔널 타입으로 선언하면 된다.
옵셔널 타입의 프로퍼티들은 자동으로 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."
Assigining Constant Preperties During Initialization
상수 프로퍼티는 초기화 단계에서 값을 할당 할 수 있다. 한번 할당되면 더 이상 변경할 수 없다.
클래스 인스턴스에서, 상수 프로퍼티는 그 프로퍼티를 갖고 있는 클래스에서만 값을 설정할 수 있다
서브 클래스에서 변경 할 수 없다.
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.)"
Default Initializers
Swift는 구조체와 클래스 모두에게 기본 생성자를 제공한다. 이 때, 모든 프로퍼티에는 기본 값이 있어야 한다.
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
quantity, purchased 는 기본 값이 할당되어 있고, name의 경우 옵셔널이기 때문에 nil로 할당된다.
따라서 위의 경우 swift가 기본 생성자를 통해 인스턴스를 생성했다.
Memberwise Initializers for Structure Types
구조체는 custom 생성자가 없을 때, 자동으로 멤버 생성자를 갖게 된다.
기본 생성자와는 다르게, 구조체의 저장 프로퍼티에 기본 값이 없어도 구조체는 멤버 생성자를 갖게 된다.
멤버 생성자는 구조체 인스턴스 멤버 프로퍼티를 초기화하는 간편한 방법이다.
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"
Initializer Delegation for Value Types
생성자는 다른 생성자를 호출할 수 있다. 이를 initializer delegation 이라 한다.
값 타입과 클래스 타입은 서로 다른 initializer delegation 방법이 있다.
값 타입(구조체, 열거형)은 상속을 지원하지 않기 때문에 상대적으로 단순하다. 따라서 오로지 자신이 갖고 있는 다른 생성자를 호출하는데 사용한다.
클래스 타입은 다른 클래스를 상속 받을 수 있기 때문에 다르다. 상속받게 되는 모든 프로퍼티에 대한 책임을 갖기 때문이다. 이러한 문제는 아래에서 다루겠다.
값 타입에서는 self.init 을 통해 같은 타입 내에 있는 다른 생성자를 호출할 수 있다. 또한 self.init 은 생성자 내에서만 호출이 가능하다.
값 타입에서 커스텀 생성자를 정의한다면, 더 이상 기본 생성자(멤버 생성자) 를 사용할 수 없게 된다.
만약 기본생성자와 멤버 생성자, 커스텀 생성자를 모든 쓰고 싶다면 커스텀 생성자를 extension 에 작성하자!
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)
}
}
init(){}
Size(width: 0, height: 0), Point(x: 0.0, y: 0.0) 을 만드는 기본생성자를 호출한다.
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
init(origin: Point, size: Size) {...}
이는 구조체의 멤버 생성자와 동일한 역할을 한다.
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)
init(center: Point, size: Size) {...}
self.init 을 통해 다른 생성자에게 위임한다.(delegate)
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)
다음 편 보기
2022.01.27 - [Swift] - [Swift] Initialization - 2편 (Class Inheritance & Initialization)
'Swift' 카테고리의 다른 글
[Swift] Initialization - 3편 (Failable Initializers) (0) | 2022.02.02 |
---|---|
[Swift] Initialization - 2편 (Class Inheritance & Initialization) (0) | 2022.01.27 |
[Swift] Structure vs Class 무엇을 골라야 할까? (0) | 2022.01.14 |
[Swift] Queues & Threads - Concurrency by Tutorials 2편 (0) | 2022.01.13 |
[Swift] Inheritance (1) | 2022.01.12 |