Swift 뿌수기 - Initialization

Wonbi·2022년 8월 31일
2

Swift 뿌수기

목록 보기
8/12

✅학습 내용

💎 Initialization

Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that’s required before the new instance is ready for use.

  • 초기화 (initialization) 는 사용할 클래스나, 구조체, 또는 열거형 인스턴스를 준비하는 과정입니다. 이 과정은 인스턴스의 각 저장 속성마다 초기 값을 설정하는 것 그리고 새 인스턴스를 사용하기 전에 필수인 다른 어떤 설정이나 초기화를 하는 걸 포함합니다.

  • 하나의 특정한 타입의 새 인스턴스를 생성하고자 호출할 수 잇는 특수한 함수 같은, 이니셜라이저 (initializers) 를 정의함으로써 이 초기화 과정을 구현한다. Objective-C의 이니셜라이저와는 다르게, 스위프트의 이니셜라이저는 값을 반환하지 않는다. 이니셜라이저의 가장 큰 목표는 새 인스턴스가 최초로 사용되기 전에 올바르게 초기화하도록 보장하는 것이다.

  • 클래스 타입 인스턴스는, 그 클래스의 인스턴스 해제 직전에 자신만의 정리를 하는, 디이니셜라이저 (deinitializers) 도 구현 할 수 있다. 디이니셜라이저에 대한 더 많은 정보는 Deinitialization 여기에 있다.

💎 저장 프로퍼티에 초기 값 설정하기

  • 클래스와 구조체는 각자의 인스턴스를 생성하는 시점까지 반드시 (must) 자신의 모든 저장 프로퍼티에 적절한 초기 값을 설정해야 한다. 저장 프로퍼티를 결정하지 않은 상태로 둘 수 없다.

  • 저장 프로퍼티의 초기 값은 이니셜라이저 안에서, 또는 프로퍼티 정의 부분에서 기본 프로퍼티 값을 할당함으로써 설정할 수 있다.

    저장 프로퍼티에 기본 값을 할당하거나, 이니셜라이저 안에서 자신의 초기 값을 설정할 땐, 어떤 프로퍼티 관찰자 호출도 없이, 그 프로퍼티 값을 직접 설정합니다.

✏️ 이니셜라이저

  • 이니셜라이저 (initializers) 는 특정 타입의 새 인스턴스를 생성하기 위해 호출한다. 가장 단순한 형식의 이니셜라이저는 매개변수가 없는 인스턴스 메서드 같이 init키워드를 써서 작성한다.
init() {
  // 여기서 블라블라 초기화를 함
}
  • 아래 예지는 화씨 척도로 표현한 온도를 저장하는 Fahrenheit라는 구조체를 정의한다. Fahrenheit 구조체에는 Double 타입인 temperature 라는 저장 프로퍼티가 하나 있다.
struct Fahrenheit {
  var temperature: Double
  init() {
    temperature = 32.0
  }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// "The default temperature is 32.0° Fahrenheit" 를 인쇄함
  • 이 구조체는 매개변수가 없는 init 이라는 단일 이니셜라이저를 정의하는데, 이는 저장 온도를 (화씨로 물의 어는 점인) 32.0 값으로 초기화한다.

✏️ 기본 속성 값

  • 이니셜라이저 안에서 저장 프로퍼티의 초기 값으 설정할 수 있다. 아니면, 프로퍼티 선언 부분에서 기본 프로퍼티 값 (default property value) 을 지정한다. 정의할 때 프로퍼티에 초기 값을 할당함으로써 기본 프로퍼티 값을 지정한다.

    프로퍼티가 항상 동일한 초기 값을 취하면, 이니셜라이저 안에서 값을 설정하기 보단 기본 값을 제공하는 것이 좋습니다. 결과는 똑같지만, 기본 값이 프로퍼티 초기화와 그것의 선언을 더 가깝게 묶습니다. 이는 이니셜라이저를 더 짧고, 명확하게 하며 자신의 기본 값으로 프로퍼티의 타입을 추론할 수 있게 합니다. 기본 값은, 기본 초기자 (default initializer) 와 초기자 상속 (initializer inheritance) 이라는 이점도 더 쉽게 취하게 합니다.

  • 프로퍼티를 선언하는 시점에 자신의 temperature 프로퍼티에 기본 값을 제공함으로써 위의 Fahrenheit 구조체를 더 단순한 형식으로 작성할 수 있다.
struct Fahrenheit {
  var temperature = 32.0
}

💎 사용자 정의 초기화

  • 입력 매개변수와 옵셔널 타입으로, 혹은 초기화 중 상수 프로퍼티를 할당함으로써 초기화 과정을 사용자 정의할 수 있다.

✏️ 초기화 매개 변수

  • 이니셜라이저 정의 부분에서 초기화 매개변수 (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 는 100.0 임
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 는 0.0 임
  • 위 예제와 같이 여러개의 이니셜라이저를 가질 수 있다.

✏️ 매개변수 이름과 아규먼트 레이블

  • 함수 및 메서드의 매개변수와 같이, 이니셜라이저의 매개변수도 이니셜라이저 본문 안에서 사용할 매개변수 이름과 이니셜라이저를 호출할 때 사용할 아규먼트 레이블 둘 다를 가질 수 있다.

  • 하지만, 이니셜라이저는 함수와 메서드가 가진 괄호 앞 식별 함수 이름을 가지진 않는다. 그러므로, 이니셜라이저의 매개변수의 이름과 타입은 호출해야 할 이니셜라이저를 식별하는 데 특히 더 중요한 역할을 담당한다. 이러한 이유로, 아규먼트 레이블을 제공하지 않으면 스위프트가 이니셜라이저의 모든 매개변수에 자동으로 아규먼트 레이블을 제공한다.

    사실, 이니셜라이저는 이름을 가지지 않는다기 보단 모든 함수 이름이 init 으로 똑같은 경우입니다. 그래서, 이니셜라이저를 이름만으로 식별할 순 없습니다. 또한 스위프트가 아규먼트 레이블을 제공한다는 의미는 스위프트가 매개 변수 이름과 똑같은 아규먼트 레이블을 자동으로 만들어 준다는 의미입니다.

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)
  • 아규먼트 레이블을 사용하지 않고 이니셜라이저를 호출하는 것은 불가능하다. 정의한 아규먼트 레이블은 반드시 이니셜라이저가 사용해야 하며, 이를 생략하면 컴파일 에러가 일어날 것이다. 물론 뒤에 나올 와일드카트 패턴을 사용하면 무시할 수 있긴하다.

✏️ 아규먼트 레이블이 없는 이니셜라이저 매개 변수

  • 이니셜라이저 매개변수에 아규먼트 레이블을 사용하고 싶지 않으면 그 매개변수에 명시적인 아규먼트 레이블 대신 와일드 카드 패턴 (_) 을 작성하여 기본 동작을 재정의 할 수 있다.
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 는 37.0 임
  • Celsius(37.0) 라는 이니셜라이저 호출은 의도가 명확하여 아규먼트 레이블이 필요 없다. 그러므로 이름 없는 Double 값을 제공해서 호출할 수 있도록 이 이니셜라이저를 init(_ celsius: Double) 로 작성하는 게 적절하다.

✏️ 옵셔널 타입

  • 사용자 정의 타입에 논리적인 이유로 옵셔널 타입의 저장 프로퍼티가 필요한 경우(초기화 중에 값을 설정할 수 없거나, 나중에 "값 없음"이 허용될 경우), 프로퍼티를 옵셔널 타입으로 선언한다. 옵셔널 타입의 프로퍼티는 초기화 중엔 프로퍼티가 "아직 값 없음"상태인 것이 일부러 의도한 것임을 지시하도록 자동으로 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()
// "Do you like cheese?" 를 인쇄함
cheeseQuestion.response = "Yes, I do like cheese."
  • 설문 조사 (survey question) 의 응답 (response) 은 물어보기 전까진 알 수 없으므로, response 프로퍼티는 String?, 또는 “옵셔널 String” 타입으로 선언한다. SurveyQuestion 의 새 인스턴스를 초기화할 때, “아직 문자열 없음” 을 의미하는 nil 이라는 기본 값을 자동으로 할당한다.

✏️ 초기화 중 상수 속성 할당하기

  • 초기화 종료 시점까지 확실한 값을 설정하는 경우 초기화 중의 어떤 시점에든 상수 속성에 값을 할당할 수 있다. 값을 상수 프로퍼티에 한 번 설정하고 나면, 더 이상 수정할 수 없다.

클래스 인스턴스에선, (상수 프로퍼티를) 도입한 클래스의 초기화 중에만 상수 프로퍼티를 수정할 수 있습니다. 하위 클래스는 이를 수정할 수 없습니다.

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 initializer) 를 제공한다. 기본 이니셜라이저는 단순히 자신의 모든 프로퍼티에 기본 값을 설정함으로써 새로운 인스턴스를 생성합니다.
class ShoppingListItem {
  var name: String?
  var quantity = 1
  var purchased = false
}
var item = ShoppingListItem()

✏️ 구조체 타입을 위한 멤버와이즈 이니셜라이저

  • 자신만의 이니셜라이저를 어떤 것도 정의하지 않은 구조체 타입은 자동으로 멤버와이즈 이니셜라이저 (memberwise initializer) 를 받는다. 기본 이니셜라이저와 달리, 저장 프로퍼티가 기본 값을 가지지 않은 경우라도 구조체는 멤버와이즈 이니셜라이저를 받는다.

  • 멤버와이즈 이니셜라이저는 새 구조체 인스턴스의 멤버 프로퍼티 초기화를 짧게 줄인 것이다. 이름으로 새 인스턴스 속성의 초기 값을 멤버와이즈 이니셜라이저에 전달할 수 있다.

struct Size {
  var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
  • 멤버와이즈 이니셜라이저를 호출할 땐, 기본 값이 있는 어떤 프로퍼티의 값이든 생략할 수 있다. 위 예제의, Size 구조체는 heightwidth 프로퍼티 모두에 기본 값이 있다. 하나의 프로퍼티 혹은 두 프로퍼티 모두 생략할 수 있으며, 생략한 것은 이니셜라이저가 기본 값을 사용한다.
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"

0개의 댓글