Swift - 14. 초기화 Initialization

지우개·2022년 3월 31일
0

Swift study

목록 보기
3/15
post-thumbnail

초기화의 종류 2가지: Designated, convenience
초기화의 목적: 모든 멤버 초기화(1단계) + 상속받은 멤버들 customizing(2단계)

초기화는 클래스, 구조체, 열거형 인스턴스를 사용하기 위해 준비 작업을 하는 단계이다. 저장 프로퍼티의 초기값을 설정한다.
초기화는 initializer를 정의하는 것으로 구현할 수 있다. 초기화와 반대로 여러 값과 자원의 해지를 위해 deinitializer도 사용할 수 있다.

하위클래스 = subclass
상위클래스 = superclass
초기자 = initializer


저장 프로퍼티를 위한 초기값 설정 Setting Initial Values for Stored Properties

인스턴스의 저장 프로퍼티는 사용하기 전에 반드시 특정 값으로 초기화되어야 한다.

저장 프로퍼티에 초기값을 지정하는 방법
1. 이니셜라이저를 실행하여 초기값(initial value)을 할당한다.
2. 프로퍼티를 정의할 때 프로퍼티 기본값(default value)를 할당한다.

initializer에서 저장 프로퍼티에 값을 직접 설정하면 프로퍼티 옵저버가 호출되지 않고 값 할당이 수행된다.

이니셜라이저 Initializers

이니셜라이저는 특정 타입의 인스턴스를 생성한다. init 키워드를 사용한다.

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 Property Values

프로퍼티의 선언과 동시에 값을 할당하면 그 값을 초기 값으로 사용할 수 있다.


커스터마이징 초기화 Customizing Initialization

초기화 프로세스를 입력 값과 옵셔널 프로퍼티 타입 혹은 상수 값을 할당해서 커스터마이징 할 수 있다.

초기화 파라미터 Initialization Parameters

초기화 정의에 파라미터를 정의해 사용할 수 있다.
다음 코드는 temperatureInCelsius 프로퍼티를 초기화 파라미터로 입력받아 초기화에 사용하는 예제이다.

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

파라미터 이름과 인자 레이블 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)
// 인자 레이블 포함하지 않으면 컴파일 에러 발생

인자 레이블이 없는 이니셜라이저 파라미터 Initializer Parameters Without Argument Labels

코드를 작성할 때 인자 레이블을 생략하는 것이 더 명료한 경우 '_' 기호를 이용해 생략할 수 있다.

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)
// 인자 레이블 없이 Celsius 인스턴스를 초기화할 수 있다.

옵셔널 프로퍼티 타입 Optional Property Types

프로퍼티의 최초 값이 없고 나중에 추가될 수 있는 값을 옵셔널로 선언해 사용할 수 있다. 옵셔널 프로퍼티는 자동으로 nil 로 초기화된다.

초기화 중에 상수 프로퍼티 할당 Assigning Constant Properties During Initialization

이니셜라이저에서는 상수 프로퍼티에 값을 할당하는 것도 가능하다.

클래스 인스턴스에서 상수 프로퍼티는 초기화 중 그 클래스 안에서만 변경이 가능하고 서브클래스에서는 변경이 불가능하다.

프로퍼티를 let 으로 선언해서 이 프로퍼티는 처음에 초기화되면 변경되지 않는 프로퍼티라는 것을 표현할 수 있다.


기본 이니셜라이저 Default Initializers

만약 모든 프로퍼티의 초기값이 설정되어 있고, 하나의 초기자도 정의하지 않았다면 Swift는 모든 프로퍼티를 기본 값으로 초기화하는 기본 초기자를 제공한다.
즉, 기본 이니셜라이저는 프로퍼티를 정의할 때 할당한 프로퍼티 기본값으로 프로퍼티를 초기화한다.
기본 이니셜라이저를 사용하려면 1) 저장 프로퍼티의 기본값이 모두 지정되어 있고, 2) 사용자 정의 이니셜라이저가 정의되어 있지 않은 상태여야 한다.

다음 코드는 이니셜라이저를 정의하지 않았지만 Swift가 제공하는 기본 이니셜라이저 ShoppingListItem() 를 사용할 수 있음을 보여준다. 🧐

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

ShoppingListItem() 클래스의 모든 프로퍼티는 기본값을 가지고 있고 상위 클래스 없이 기본 클래스이므로 자동적으로 모든 프로퍼티를 기본값으로 설정한다.

구조체 타입을 위한 멤버와이즈 이니셜라이저 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"
struct InBody {
    var height: Double = 170.0
    var weight: Double = 70.0
}
let james: InBody = InBody(height: 180, weight: 80) // 멤버와이즈 이니셜라이저를 사용
let kevin: InBody = InBody() // 기본 이니셜라이저를 사용
let jane: InBody = InBody(height: 160) // 기본값이 있는 저장 프로퍼티는 필요한 매개변수만 사용하여 초기화 가능
let emily: InBody = InBody(weight: 80)

값 타입을 위한 이니셜라이저 위임 Initializer Delegation for Value Types

이니셜라이저에서 다른 이니셜라이저를 호출할 수 있다. 이 과정을 이니셜라이저 위임이라고 한다.
값 타입(structures, enumerations)과 클래스 타입 간 이니셜라이저 위임 동작이 다르다.
값 타입은 상속을 지원하지 않아 이니셜라이저를 자기 자신의 다른 이니셜라이저에만 사용할 수 있다.
클래스 타입은 상속이 가능하기 때문에 superclass의 이니셜라이저를 subclass에서 호출할 수 있다.

값 타입의 경우 같은 값 타입으로부터 다른 초기화 구문을 참조하기 위해 self.init 을 사용한다. 초기화 구문내에서만 호출할 수 있다.

값 타입에 대해 커스텀 이니셜라이저를 정의한다면 기본 이니셜라이저(또는 구조체의 경우 멤버와이즈 이니셜라이저)에 더이상 접근할 수 없다.

커스텀 이니셜라이저를 사용하면서 기본 이니셜라이저와 멤버와이즈 이니셜라이저도 사용하고 싶다면 커스텀 이니셜라이저를 오리지널 클래스에서 구현하지 않고 익스텐션에서 구현하면 된다.

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(), init(origin:size:), init(center: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)

// 세번째
// 내부에서 다른 초기자인 init(center: Point, size: Size)를 사용한다. 이를 호출해 초기화를 이 이니셜라이저에 위임한다.
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)

이니셜라이저를 익스텐션을 이용해 선언하면 첫번째, 두번째 이니셜라이저는 자동으로 생성되고 익스텐션에 선언한 이니셜라이저도 사용할 수 있다.


클래스 상속과 초기화 Class Inheritance and Initialization

모든 클래스의 저장 프로퍼티와 superclass로부터 상속받은 모든 프로퍼티는 초기화 단계에서 반드시 초기값이 할당되어야 한다.
Swift에서는 클래스 타입에서 모든 프로퍼티가 초기 값을 갖도록 2가지 방법을 사용한다.

지정 초기자와 편의 초기자 Designated Initializers and Convenience Initializers

지정 초기자

  • 클래스의 주 primary 초기자
  • 클래스의 모든 프로퍼티를 초기화 해야함
  • 클래스 타입은 반드시 한 개 이상의 지정 초기자 필요
init(parameters) {
    statements
}

편의 초기자

  • 옵셔널
  • 초기화 단계에서 미리 지정된 값을 사용해서 최소한의 입력으로 초기화를 할 수 있도록 해줌.
  • 편의 초기자 내에서 반드시 지정 초기자가 호출되어야 한다. (self.init())
  • convenience init
convenience init(parameters) {
	self.init()
    statements
}

클래스 타입을 위한 이니셜라이저 위임 Initializer Delegation for Class Types

지정 초기자와 편의 초기자 사이의 관계를 단순하게 하기 위해, 이니셜라이저 위임에는 3가지 규칙이 따른다.

<규칙>
1. 지정 초기자는 반드시 직계 superclass의 지정 초기자를 호출해야 한다.
2. 편의 초기자는 반드시 같은 클래스의 다른 초기자를 호출해야 한다.
3. 편의 초기자는 궁극적으로 지정 초기자를 호출해야 한다.

요약

  • 지정 초기자는 반드시 위임을 superclass로 해야한다.
  • 편의 초기자는 반드시 위임을 같은 레벨에서 해야한다.

그림에서 subclass의 편의 초기자는 같은 레벨에서 다른 지정 초기자를 호출하고, 지정 초기자는 초기화를 상위 클래스에게 위임해 상위 클래스의 지정 초기자가 호출되는 것을 확인할 수 있다.

2단계 초기화 Two-Phase Initialization

Swift에서 클래스 초기화는 2단계로 진행된다.
첫번째 단계에서는 각 저장된 프로퍼티는 초기값으로 초기화된다. 모든 저장된 프로퍼티의 상태가 결정되면 두번째 단계가 시작된다. 두번째 단계에서는 새로운 인스턴스의 사용이 준비됐다고 알려주기 전에 저장된 프로퍼티를 커스터마이징하는 단계이다.

Swift의 컴파일러는 2단계 초기화가 에러없이 끝나는 것을 보장하기 위해 4단계 안전 확인(safety-check)을 한다.

안전 확인 1단계 지정 초기자는 클래스 안에서 초기화를 superclass의 초기자에게 위임하기 전에 모든 프로퍼티를 초기화해야 한다. 메모리에서 객체는 모든 저장된 프로퍼티가 초기 상태를 가져야만 완전히 초기화된 것으로 간주하기 때문이다.

안전 확인 2단계 편의 초기자는 반드시 어떤 프로퍼티를 할당하기 전에 superclass의 초기자로 위임을 넘겨야 한다. 그렇지 않으면 상속된 값이 상위 클래스에 의해 덮어쓰인다.

안전 확인 3단계 편의 초기자는 반드시 어떤 프로퍼티를 할당하기 전에 다른 초기자로 위임을 넘겨야 한다. 그렇지 않으면 편의 초기자에 의해 할당된 값을 다른 클래스의 지정 초기자에 의해 덮어쓰인다.

안전 확인 4단계 이니셜라이저는 초기화의 1단계가 끝나기 전에는 self의 값을 참조하거나 어떤 인스턴스 프로퍼티, 메소드 등을 호출하거나 읽을 수 없다.

1단계

  • 지정 또는 편의 초기자는 클래스에서 호출된다.
  • 클래스에 새로운 인스턴스에 대한 메모리가 할당된다. (메모리는 아직 초기화되지 않음)
  • 해당 클래스의 지정 초기자는 클래스가 도입한 모든 저장된 프로퍼티가 값이 있는지 확인한다. 이 저장된 프로퍼티들의 메모리가 초기화된다.
  • 지정 초기자가 (자체 저장된 프로퍼티와 동일한 작업을 수행하기 위해) superclass 이니셜라이저에 전달된다.
  • 최상위 체인에 도달할 때까지 클래스 상속 체인 위로 계속된다.
  • 최상위 체인에 도달하고, 체인 마지막 클래스의 모든 저장된 프로퍼티가 값을 가지고 있다면 인스턴스의 메모리가 완벽하게 초기화 되었다고 간주하고 1단계가 완료된다.

2단계

  • 체인의 최상위에서 아래로 내려가면 체인에 각 지정 초기자는 인스턴스를 커스터마이징할 수 있다. 초기자는 이제 self로 접근할 수 있고, 프로퍼티 수정이 가능하며 인스턴스 메소드를 호출하는 등의 작업을 수행할 수 있다.
  • 체인의 모든 편의 초기자는 인스턴스를 커스터마이징하고 self 로 작업할 수 있다.

이니셜라이저의 상속과 오버라이딩 Initializer Inheritance and Overriding

Swift에서는 기본적으로 subclass에서 superclass의 이니셜라이저를 상속하지 않는다. 이는 superclass의 이니셜라이저가 무분별하게 상속되면 복잡해져 subclass에서 이것들이 잘못 초기화되는 것을 막기 위함이다.

만약 클래스에서 모든 프로퍼티의 초기 값이 지정되어 있고 아무런 커스텀 초기자를 선언하지 않았다면 기본 초기자 init()을 사용할 수 있다.
superclass의 초기자를 오버라이드하기 위해서는 subclass에서 그 초기자에 override 키워드를 붙이고 재정의한다.

다음은 클래스를 생성하고 그의 subclass에서 초기자를 오버라이드 해 사용하는 예제이다.

class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
}

// 초기값이 지정한대로인지 확인
let vehicle = Vehicle()
print("Vehicle: \(vehicle.description)")
// Vehicle: 0 wheel(s)

// subclass에서 superclass의 초기자를 오버라이드함
class Bicycle: Vehicle {
    override init() {
        super.init()
        numberOfWheels = 2
    }
}

// 인스턴스 생성 후 초기 값이 변한 것 확인
let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Bicycle: 2 wheel(s)

아래 예제는 초기화 구문에서 color 프로퍼티만 설정한다. 이 구문은 super.init()을 명시적으로 호출하는 대신 상위 클래스의 초기화 구문을 암시적으로 호출함으로써 프로세스를 완료한다.

class Hoverboard: Vehicle {
    var color: String
    init(color: String) {
        self.color = color
        // super.init() implicitly called here
    }
    override var description: String {
        return "\(super.description) in a beautiful \(color)"
    }
}

let hoverboard = Hoverboard(color: "silver")
print("Hoverboard: \(hoverboard.description)")
// Hoverboard: 0 wheel(s) in a beautiful silver
// Vehicle 초기화 구문에 의해 제공된 바퀴의 기본 갯수를 사용함

자동 초기자 인스턴스 Automatic Initializer Inheritance

하위 클래스는 상위 클래스의 초기자를 기본적으로 상속하지 않지만, 특정 상황에서 자동으로 상속받는다.
하위 클래스에서 새로 추가한 모든 프로퍼티에 기본 값을 제공하면 다음 두 가지 규칙이 적용된다.
규칙 1 하위 클래스가 지정 초기자를 정의하지 않으면 자동으로 상위 클래스의 모든 지정 초기자를 상속한다.
규칙 2 하위 클래스가 상위 클래스의 지정 초기자를 모두 구현한 경우 자동으로 모든 상위 클래스의 편의 초기자를 자동으로 상속받는다.

규칙 2에 따라 서브클래스는 수퍼클래스의 지정 초기자를 서브클래스의 편의 초기자로 구현 가능하다.

지정 초기자와 편의 초기자의 사용

다음은 지정 초기자, 편의 초기자, 그리고 자동 초기자 상속의 사용 예제이다.
여기서는 Food, RecipeIngredient, ShoppingListItem이라는 3개의 클래스 계층을 정의하고 초기자의 상호작용을 보여준다.

class Food {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}

다음은 convenience init()에서 지정 초기자 init(name: String)이 호출되는 형태를 그림으로 나타낸 것이다.

let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon"

let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]"
class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

상위 클래스의 init(name:) 초기자를 상속받아 지정 초기자를 생성하고 그 지정 초기자를 편의 초기자 convenience init(name: String)에서 오버라이딩해 사용한다.

RecipeIngredient에서 초기자가 사용되는 구조는 다음과 같다.

RecipeIngredient 클래스는 다음 3가지 형태의 초기자를 이용해 인스턴스를 생성할 수 있다.

let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)

마지막으로 RecipeIngredient를 상속받아 생성한 ShoppingListItem 클래스에서의 초기자에 대해 살펴보겠다.

class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}

ShoppingListItem 클래스에서 purchased 프로퍼티 값은 언제나 false를 시작값으로 사용하기 때문에 이 값을 변경하는 초기자를 제공하지 않는다. 🧐
ShoppingListItem 클래스는 새로 생성한 모든 프로퍼티에 대해 기본 값을 제공하고 새로운 초기자를 정의하지 않았기 때문에 자동으로 상위 클래스의 모든 지정 초기자와 편의 초기자를 상속받는다.

ShoppingListItem 클래스에서 초기자가 호출되는 구조는 다음과 같다.

var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    print(item.description)
}
// 1 x Orange juice ✔
// 1 x Bacon ✘
// 6 x Eggs ✘

실패 가능한 초기자 Failable Initializers

초기화 과정 중에 실패할 가능성이 있는 초기자를 init 뒤 물음표(?)를 사용해 표시할 수 있다.

동일한 파라미터 타입과 이름으로 실패 가능한 초기자와 실패 불가능한 초기자를 정의할 수 없다.

실패 가능한 초기자는 반환값으로 옵셔널 값을 생성한다. 초기화에 실패하는 부분에서 nil을 반환하는 코드를 작성해 초기화가 실패했음을 나타낸다.

엄밀히 말하면 초기자 init은 값을 반환하지 않는다. 초기화 실패를 나타내기 위해 return nil은 사용하지만, 초기화 성공을 나타내기 위해서는 return 키워드를 사용하지 않는다.

다음 코드는 숫자형을 위해 정의되어 있는 실패 가능한 초기자 Int(exactly:)를 사용한 예제이다.

let wholeNumber: Double = 12345.0
let pi = 3.14159

if let valueMaintained = Int(exactly: wholeNumber) {
    print("\(wholeNumber) conversion to Int maintains value of \(valueMaintained)")
}
// Prints "12345.0 conversion to Int maintains value of 12345"

let valueChanged = Int(exactly: pi)
// valueChanged is of type Int?, not Int

if valueChanged == nil {
    print("\(pi) conversion to Int does not maintain value")
}
// Prints "3.14159 conversion to Int does not maintain value"

열거형에서 사용하는 실패 가능한 초기자 Failable Initializers for Enumerations

열거형에서도 실패 가능한 초기자를 사용할 수 있다.
Raw 값을 초기자 인자로 넣어 초기화에 사용할 수 있다.

초기자 실패의 생성 Propagation of Initialization Failure

실패 가능한 초기자에서 실패가 발생하면 즉시 관련된 초기자가 중단된다.

실패 가능한 초기자를 실패 불가능한 초기자에 위임해 특정 상황에서만 실패하는 초기자로 만들 수 있다.

// Product의 name이 없거나 CartItem의 quantity가 1미만인 경우 초기화 실패하도록 구현한 예제
class Product {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

class CartItem: Product {
    let quantity: Int
    init?(name: String, quantity: Int) {
        if quantity < 1 { return nil }
        self.quantity = quantity
        super.init(name: name)
    }
}

실패 가능한 초기자의 오버라이딩 Overriding a Failable Initializer

상위 클래스의 실패 가능한 초기자를 하위 클래스에서 실패 불가능한 초기자로 오버라이딩 할 수 있다.

실패 가능한 init! 초기자 The init! Failable Intializer

실패 가능한 초기자 init?init!으로 오버라이딩 하거나 위임해서 사용할 수 있다.


필수 초기자 Required Initializers

모든 하위 클래스에서 반드시 구현해야 하는 초기자에는 required 키워드를 붙인다.


클로저나 함수를 이용해 기본 프로퍼티 값을 설정하기 Setting a Default Property Value with a Closure or Function

기본 값 설정에 복잡한 계산이 필요하다면 클로저나 함수를 이용해 값을 초기화할 수 있다.

class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
    }()
}
// 클로저가 실행된 후 반환 타입이 SomeType인 SomeValue를 값으로 갖게 된다.

면접 질문

1. Convinience init에 대해 설명하시오.

보조 이니셜라이저로, 클래스의 원래 이니셜라이저인 init을 도와주는 역할을 한다.

편의 초기자는 초기화 단계에서 미리 지정된 값을 사용해 최소한의 입력으로 초기화를 할 수 있도록 해주는 초기자이다.
편의 초기자 내에서 반드시 지정 초기자(Designated init)가 호출되어야 한다.


참고
https://jusung.gitbook.io/the-swift-language-guide/language-guide/14-initialization
https://applecider2020.tistory.com/17
https://ios-development.tistory.com/239

0개의 댓글