초기화 위임
값 타입인 구조체와 열거형은 코드 중복을 피하기 위해서 한 이니셜라이저가 다른 이니셜라이저에게 일부 초기화를 위함하는 초기화 위임을 간단하게 구현 가능하다. 하지만, 참조 타입인 클래스는 불가능 하니 주의!
구조체와 열거형에서 이니셜라이저가 다른 이니셜라이저를 호출하려면 self.init
키워드를 사용한다. 그리고 반드시 이니셜라이저 안에서만 사용 가능하고, 이것을 사용한다는 것은 사용자 정의 이니셜라이저를 정의하고 있다는 뜻이 된다.
하지만 저번 게시글에서 사용자 정의 이니셜라이저를 정의하면 기본 이니셜라이저와 멤버와이즈 이니셜라이저를 사용할 수 없다고 했는데, 초기화를 위임 하기 위해서는 최소 두 개 이상의 사용자 정의 이니셜라이저를 정의해야 한다.
enum Student {
case elementary, middle, heigh, adult
case none
//사용자 정의 이니셜라이저가 있으면, init() 메서드를 구현해줘야 기본 이니셜라이저 사용가능
init() {
self = .none
}
// 사용자 이니셜 라이저 1
init(age KoreanAge: Int) {
switch KoreanAge {
case 8...13:
self = .elementary
case 14...16:
self = .middle
case 17...19:
self = .heigh
case 20...:
self = .adult
default:
self = .none
}
}
// 사용자 이니셜라이저 2
init(bornAt: Int, currentYear: Int) {
self.init(age: currentYear - bornAt + 1) //첫번째 이니셜라이저를 호출함 (초기화 위임)
}
}
var Seogun: Student = Student(age: 27) //adult
Seogun = Student(bornAt: 2012, currentYear: 2022) //elementary
위 코드를 살펴보자면, 두 개의 사용자 정의 이니셜라이저가 있고, 첫 번째 이니셜라이저는 나이게 맞게 구분되어있어서 이니셜라이저를 초기화 하고, 두 번째 사용자는 태어난 년도와 현재 년도를 전달 받아 나이를 계산한 뒤에 첫 번째 이니셜라이저에게 초기화 위임을 한다.
이렇게 해서 코드를 중복으로 사용하지 않고 효율적으로 여러 case
의 이니셜라이저를 만들 수 있게 된다.
실패 가능한 이니셜라이저
이니셜라이저를 통해 인스턴스를 초기화할 수 없는 몇가지 예외 상황이 있는데, 대표적으로 이니셜라이저의 전달인자로 잘못된 값이나 적절치 못한 값이 전달 되었을 때 이니셜라이저는 인스턴스 초기화에 실패할 수 있다.
이니셜라이저를 정의할 때 이러한 실패 가능성을 염두에 두기도 한다. 이런 실패 가능성을 가진 이니셜라이저를 실패 가능한 이니셜라이저 Failable initializer이라고 부른다.
실패 가능한 이니셜라이저는 클래스, 구조체, 열거형 모두에서 정의할 수 있고, 실패 했을 때 nil
을 반환 해주므로 반환 타입은 당연히 옵셔널로 지정된다.
따라서 실패 가능한 이니셜라이저는 init
이 아닌 init?
키워드를 사용하게 된다.
이니셜라이저 매개변수
실패하지 않은 매개변수와 실패 가능한 이니셜라이저는 똑같은 이름의 매개변수 타입을 가질수 없다.
실패 가능한 이니셜라이저는 특정 값을 반환하지 않기 때문에 초기화가 실패하면 return nil
반환, 반대로 성공하면 return
을 할당해 초기화의 성공과 실패만을 표현할 뿐, 실제 값을 반환하지는 않는다.
값이 잘못 전달되면 인스턴스 초기화에 실패할 수 있는데, 실패 가능한 이니셜라이저를 사용하면 잘못된 전달인자 전달받았을 때 초기화하지 않을 수 있다.
class Person {
let name: String
var age: Int?
init?(name: String) {
if name.isEmpty {
return nil
} else {
self.name = name
}
}
init?(name: String, age: Int) {
if name.isEmpty || age < 0 {
return nil
} else {
self.name = name
self.age = age
}
}
}
let Seogun: Person? = Person(name: "서근")
if let person: Person = Seogun {
print(person.name)
} else {
print("Person class 초기화에 실패했습니다")
} //서근
let Mijin: Person? = Person(name: "미진", age: -20)
if let person: Person = Mijin {
print(person.name)
} else {
print("Person class 초기화에 실패했습니다")
} //Person class 초기화에 실패했습니다
let Cheolsu: Person? = Person(name: "", age: 10)
if let person: Person = Cheolsu {
print(person.name)
} else {
print("Person class 초기화에 실패했습니다")
} //Person class 초기화에 실패했습니다
실패 가능한 이니셜라이저는 클래스와 구조체에서도 유용하게 사용되지만, 특히 열거형에서 더 유용하게 사용된다. 특정 case
에 맞지 않는 값이 들어오게 된다면 생성에 실패할 수 있다.
또는 rawValue
로 초기화할 때, 잘못된 rawValue
가 전달된다면 열거형 인스턴스를 생성하지 못한다. 따라서rawValue
를 통한 이니셜라이저는 기본적으로 실패 가능한 이니셜라이저로 제공된다.
enum Student: String {
case elementary = "초등학생", middle = "중학생", heigh = "고등학생", adult = "성인"
init?(age KoreanAge: Int) {
switch KoreanAge {
case 8...13:
self = .elementary
case 14...16:
self = .middle
case 17...19:
self = .heigh
case 20...:
self = .adult
default:
return nil
}
}
init?(bornAt: Int, currentYear: Int) {
self.init(age: currentYear - bornAt + 1)
}
}
var Seogun: Student? = Student(age: 10) // 초등학생
Seogun = Student(bornAt: 2021, currentYear: 2022) // nil
Seogun = Student(rawValue: "유치원생") //nil
Seogun = Student(rawValue: "중학생") //middle
읽어주셔서 감사합니다 🤟
'SWIFT > Grammar' 카테고리의 다른 글
Swift : 기초문법 [접근 제어 - open, public, internal, fileprivate, private] (0) | 2022.01.18 |
---|---|
Swift : 기초문법 [인스턴스 #4 클로저 사용 프로퍼티 기본값, 디이니셜라이저] (2) | 2022.01.15 |
Swift : 기초문법 [인스턴스 #2 기본 이니셜라이저, 멤버와이즈 이니셜라이저] (0) | 2022.01.15 |
Swift : 기초문법 [인스턴스 #1 이니셜라이저, 매개변수) (0) | 2022.01.15 |
Swift : 기초문법 [메서드 #3 타입 메서드] (0) | 2022.01.14 |