[Swift] Initialization(1)

상 원·2022년 7월 20일
0

Swift

목록 보기
23/31
post-thumbnail

클래스, 구조체, 열거형의 인스턴스를 사용하기 위해 준비하는 것.
인스턴스의 저장 프로퍼티 초기값을 정할 수 있다.

저장 프로퍼티 초기값 지정하기

구조체나 클래스의 인스턴스가 생성될 때 저장 프로퍼티의 값이 다 초기화되어야 함!
요 프로퍼티들은 선언할 때 초기화될 수도 있고, 이니셜라이저로 초기화될 수도 있음.

Initializer

이니셜라이저는 특정 타입의 새로운 인스턴스를 생성하기 위해 호출됨!
제일 기본적인 형식은 매개변수가 없는 형식인데,

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
}

요런식으루.

Customizing Initialization

Initialization Parameters

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이 달라짐!

Parameter Names and Argument Labels

함수나 메소드처럼 매개변수 이름이랑 우리가 호출할 때 쓰는 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

이런식으로 매개변수 이름을 안써주면 안됨!!!!!

Initializer Parameters Without Argument Labels

매개변수 이름을 안 써주고 싶다면?

_ 요걸 써주면 된다. 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."

요런식으로 클래스 인스턴스 만들 때 옵셔널이 아닌 text만 초기화해주고, response는 나중에 값을 넣어줘도 된다.

Assigning Constant Properties 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.)"

let으로 선언하면 요 선언 뒤에는 더이상 바뀌지 않지만, 초기화할 때는 바꿔줄 수 있다.

기본 이니셜라이저

간단함! 뭔가 굳이 초기화하지 않아도 될 때, default initializer가 자동으로 생성되고 실행되는 거임.
예제를 보면 바로 이해된다.

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()

이런식으로 ShoppingListItem 클래스의 모든 요소가 이미 초기화가 되어 있거나 옵셔널로 선언돼 있어서 굳~~~이 이니셜라이저가 쓰일 필요가 없을 때, default initializer가 생성돼서 매개변수 없이 인스턴스를 생성할 때 실행된다.

Memberwise Initializers for Structure Types

구조체의 멤버별 이니셜라이저도 있음!
이것도 자동으로 생성되는 건데, 이니셜라이저를 따로 만들어주지 않았을 경우에 생성됨.

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 InitializerCustom Initializer 를 만들어두지 않았을 때만 자동으로 생성되고, 만약 하나라도 init을 선언했다면 생성이 안됨!
근데 Default Initializer도 쓰고, Custom Initializer도 쓰고 싶다면?
Extension을 사용해서 거기에다 Custom Initializer를 써주면 됨!

Initializer Delegation for Value Types

다른 이니셜라이저를 호출해서 사용할 수도 있다. 코드 재사용을 막아준다는 장점이 있는데, 요걸 Initializer Delegation 이라고 함!

이 delegation은 두 타입에 따라 다르게 적용됨!

  • Value type
    값 타입은 상속이 안되기 때문에 그냥 자기 타입 안에 있는 이니셜라이저만 delegation 할 수 있다.
  • Class type
    클래스 타입은 상속이 가능하기 때문에 상속받는 모든 저장 프로퍼티를 초기화해야 하는 의무가 있음!!

일단 값 타입부터 살펴보면,

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를 사용해 자기 자신의 이니셜라이저를 재사용할 수 있다.

profile
ios developer

0개의 댓글