초기화 과정은 새로운 인스턴스를 사용할 준비를 하기 위하려 저장 프로퍼티의 초깃값을 설정하는 등의 일을 한다.
initializer를 정의하면 초기화 과정을 직접구현할 수 있고, 이렇게 구현된 이니셜라이저는 새로운 인스턴스를 생성할 수 있는 특별한 method 가 된다.
init 메서드는 클래스, 구조체, 열거형 등의 구현부 또는 해당 타입의 익스텐션 구현부에 위치한다.
다만, 클래스의 지정이니셜라이저는 익스텐션에서 구현해줄 수 없다 -> 익스텐션 초기화 파트에서 볼예정 Coming soon..
class someClass {
init(){
}
}
struct someStruct {
init() {
}
}
enum SomeEnum {
case someCase
init() {
// 💬 열거형은 초기화할때 반드시 case 중 하나가 되어야합니다.
self = .someCase
}
}
### 1.1 프로퍼티 기본값 (default value)
- 이니셜라이저가 실행될때 저장 프로퍼티에 적절한 초기값을 할당해야한다. (초기화 후에 값이 확정되지 않은 프로퍼티는 존재 x)
- 프로퍼티를 정의할 때 프로퍼티 기본값(default value)을 할당하면 이니셜라이저에서 따로 초기활르 하지 않아도 된다
-> 프로퍼티의 기본값으로 저장 프로퍼티의 값이 초기화 된다.
> **초기화와 프로퍼티 감시자**
> 이니셜라이저를 통해 초깃값 할당하거나 프로퍼티 기본값을 통해 처음의 저장 프로퍼티가 초기화 될때는 프로퍼티 감시자 메소드가 호출안됨
```swift
struct someStruct {
var someVar: Int
init() {
someVar = 2 //초기값할당
}
}
struct someStruct {
var someVar: Int = 2
}
1.2 이니셜라이저 매개변수
이니셜라이져도 매개변수를 가질 수 있다.
사용자 정의 이니셜라이저를 만들면 기존의 기본 이니셜라이저( init() )는 별도로 구현하지 않는 이상 사용할 수 없다.
### 1.3 옵셔널 프로퍼티 타입
아래와 같은 저장 프로퍼티는 옵셔널로 선언해도 된다.
- 초기화 과정에서 값을 초기화 하지 않아도 되는, 즉 인스턴스가 사용되는 동안에 값을 꼭 갖지 않아도 되는 저장 프로퍼티
- 초기화 과정에서 값을 지정해주기 어려운 저장 프로퍼티
옵셔널로 선언한 저장 프로퍼티를 초기화 과정에서 값을 할당해주지 않는다면 자동으로 `nil` 이 할당된다!
```swift
class Person {
var name: String
var age: Int?
init(name: String) {
self.name = name
}
}
1.4 상수 프로퍼티
상수로 선언된 저장 프로퍼티는 인스턴스를 초기화 하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없다.
클래스 인스턴스의 상수 프로퍼티는 프로퍼티가 정의된 클래스에서만 초기화 할 수 있다.
해당 클래스를 상속받은 자식클래스의 initializer 에서는 부모클래스의 상수 프로퍼티 값 초기화가 불가함
class Person {
let name: String
var age: Int?
init(name: String) {
self.name = name
}
}
let avery: Person = Person(name: "avery")
avery.name = "chanhee" // 오류
1.5 기본이니셜라이저와 멤버와이즈이니셜라이저
지금까지는 사용자정의이니셜라이저 에 대해 설명했다.
만약 사용자정의이니셜라이저를 정의해주지 않는다면 ?
-> 클래스나 구조체는 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 기본 이니셜라이저를 사용한다.
=> 즉, 기본이니셜라이저는 프로퍼티기본값으로 프로퍼티 초기화 하여 인스턴스를 생성 ✨
위의 내용을 정리하면
💨 기본이니셜라이저 : 저장프로퍼티의 기본값이 모두 지정되어 있고, 동시에 사용자정의 이니셜라이저가 정의되어 있지 않은 상태에서 제공
근데, 저장프로퍼티 선언할때 기본값이 없으면 이니셜라이저에 초기값을 설정해야하는데 프로퍼티 하나 때문에 매번 이니셜라이저를 추가하고 변경하는 것은 일이다
-> 그래서 등장한게 멤버와이즈이니셜라이저! (근데 구조체에만 있음!)
멤버와이즈이니셜라이져는 구조체에서 사용자정의이니셜라이저를 구현하지 않으면 프로퍼티의 이름으로 매개변수를 갖는 이니셜라이저이다.
!! 클래스는 지원하지 않는다는게 포인트! 이것은 구조체만 가능합니다!
1.6 초기화 위임
값타입인 구조체와 열거형은 코드의 중복을 피하기 위하여 이니셜라이저가 다른 이니셜라이저에게 일부 초기화를 위임하는 초기화 위임을 구현할 수있다. (간단하게)
근데 클래스는 상속을 지원하므로 안된다!
self.init 을 이용하면 값타입에서 이니셜라이저가 다른 이니셜라이저를 호출할 수 있다.
=> self.init 은 당연히 이니셜라이저안에서만 사용이 가능한데, self.init 을 사용한다는 것 자체가 사용자정의 이니셜라이저를 사용한다는 것을 의미한다
=> 결국 초기화 위임을 하려면 최소 2개 이상의 사용자 정의 이니셜라이저를 정의해야한다.
enum Student {
case elementary, middle, high
case none
// 사용자정의 이니셜라이저가 있는 경우, init() 메서드를 구현해주어야 기본 이니셜라이저를 사용할 수 있습니다.
init() {
self = .none
}
init(koreanAge: Int) { // 첫 번째 사용자정의 이니셜라이저
switch koreanAge {
case 8...13:
self = .elementary
case 14...16:
self = .middle
case 17...19:
self = .high
default:
self = .none
}
}
init(bornAt: Int, currentYear: Int) { // 두 번째 사용자정의 이니셜라이저
self.init(koreanAge: currentYear - bornAt + 1)
}
}
var younger: Student = Student(koreanAge: 16)
print(younger) // middle
younger = Student(bornAt: 1998, currentYear: 2016)
print(younger) // high
1.7 실패가능한 이니셜라이저
이니셜라이저를 초기화할때 인스턴스를 초기화할수없는 여러가지 예외상황에서 사용가능하다
실패가능한 이니셜라이져 (Failable Initializer) : 초기화 실패 가능성을 내포한 이니셜라이저
클래스, 구조체, 열거형 등에 모두 정의가능하다.
실패시 nil 을 반환 -> 옵셔널로 지정된다. => init? 키워드 사용
특히 열거형에서 유용 -> 특정 case 에 맞지 않는 값이 들어오면 생성에 실패할 수 있다.
// 코드 11-9 실패 가능한 이니셜라이저
class Person {
let name: String
var age: Int?
init?(name: String) {
if name.isEmpty {
return nil
}
self.name = name
}
init?(name: String, age: Int) {
if name.isEmpty || age < 0 {
return nil
}
self.name = name
self.age = age
}
}
let yagom: Person? = Person(name: "yagom", age: 99)
if let person: Person = yagom {
print(person.name)
} else {
print("Person wasn’t initialized")
}
// yagom
let chope: Person? = Person(name: "chope", age: -10)
if let person: Person = chope {
print(person.name)
} else {
print("Person wasn’t initialized")
}
// Person wasn’t initialized
let eric: Person? = Person(name: "", age: 30)
if let person: Person = eric {
print(person.name)
} else {
print("Person wasn’t initialized")
}
// Person wasn’t initialized
사용자 정의 연산을 통해 저장프로퍼티 기본값을 설정하고자 한다면 클로저나 함수를 사용하여 프로퍼티 기본값을 제공할 수 있다.
클로저와 함수의 반환타입은 프로퍼티의 타입과 일치해야한다.
⚠️ 주의 : 클로저의 실행시점은 초기화할때 인스턴스의 다른 프로퍼티 값이 설정되기 전이다.
즉, 클로저 내부에서는 인스턴스의 다른 프로퍼티를 사용하여 연산할 수 없다. / 다른 프로퍼티에 기본값이 있더라도
클로저 내부에서 self 프로퍼티 사용 및 인스턴스 메소드 호출 불가
// 코드 11-11 클로저를 통한 프로퍼티 기본값 설정
class SomeClass {
let someProperty: SomeType = {
// 새로운 인스턴스를 생성하고 사용자정의 연산을 통한 후 반환해줍니다.
// 반환되는 값의 타입은 SomeType과 같은 타입이어야 합니다.
return someValue
}**()** // ✅ 클로저 뒤에 소괄호가 붙는 이유는 클로저를 실행하기 위해서다. -> 없다면 그냥 클로저 그자체임.
}
2. 인스턴스 소멸
클래스 의 인스턴스는 디이니셜라이저 (deinitializer / deinit ) 를 구현할 수 있다.
-> 메모리에서 해제되기 직전 클래스 인스턴스와 관련하여 원하는 정리 작업 구현 가능
특징
클래스에는 deinit 을 단 하나만 구현가능
매개변수 가지지 않고 소괄호도 적어주지 않음
자동으로 호출되어 별도의 코드로 호출 X
// 코드 11-13 디이니셜라이저의 구현
class SomeClass {
deinit {
print("Instance will be deallocated immediately")
}
}
var instance: SomeClass? = SomeClass()
instance = nil // Instance will be deallocated immediately
인스턴스 생성 및 소멸
1. 인스턴스의 생성
init 메서드는 클래스, 구조체, 열거형 등의 구현부 또는 해당 타입의 익스텐션 구현부에 위치한다.
} }
struct someStruct { init() {
}
enum SomeEnum { case someCase
}
1.2 이니셜라이저 매개변수
이니셜라이져도 매개변수를 가질 수 있다.
사용자 정의 이니셜라이저를 만들면 기존의 기본 이니셜라이저( init() )는 별도로 구현하지 않는 이상 사용할 수 없다.
}
1.4 상수 프로퍼티
1.5 기본이니셜라이저와 멤버와이즈이니셜라이저
지금까지는 사용자정의이니셜라이저 에 대해 설명했다. 만약 사용자정의이니셜라이저를 정의해주지 않는다면 ? -> 클래스나 구조체는 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 기본 이니셜라이저를 사용한다. => 즉, 기본이니셜라이저는 프로퍼티기본값으로 프로퍼티 초기화 하여 인스턴스를 생성 ✨
위의 내용을 정리하면
근데, 저장프로퍼티 선언할때 기본값이 없으면 이니셜라이저에 초기값을 설정해야하는데 프로퍼티 하나 때문에 매번 이니셜라이저를 추가하고 변경하는 것은 일이다 -> 그래서 등장한게 멤버와이즈이니셜라이저! (근데 구조체에만 있음!)
멤버와이즈이니셜라이져는 구조체에서 사용자정의이니셜라이저를 구현하지 않으면 프로퍼티의 이름으로 매개변수를 갖는 이니셜라이저이다. !! 클래스는 지원하지 않는다는게 포인트! 이것은 구조체만 가능합니다!
1.6 초기화 위임
self.init 을 이용하면 값타입에서 이니셜라이저가 다른 이니셜라이저를 호출할 수 있다. => self.init 은 당연히 이니셜라이저안에서만 사용이 가능한데, self.init 을 사용한다는 것 자체가 사용자정의 이니셜라이저를 사용한다는 것을 의미한다 => 결국 초기화 위임을 하려면 최소 2개 이상의 사용자 정의 이니셜라이저를 정의해야한다.
1.7 실패가능한 이니셜라이저
이니셜라이저를 초기화할때 인스턴스를 초기화할수없는 여러가지 예외상황에서 사용가능하다
열거형에서 활용
1.8 함수를 사용한 프로퍼티 기본값 설정
⚠️ 주의 : 클로저의 실행시점은 초기화할때 인스턴스의 다른 프로퍼티 값이 설정되기 전이다.
2. 인스턴스 소멸
클래스
의 인스턴스는 디이니셜라이저 (deinitializer /deinit
) 를 구현할 수 있다. -> 메모리에서 해제되기 직전 클래스 인스턴스와 관련하여 원하는 정리 작업 구현 가능특징
deinit
을 단 하나만 구현가능var instance: SomeClass? = SomeClass() instance = nil // Instance will be deallocated immediately