객체를 생성할때 초기값을 생성하는 부분과 끝나는 부분에 대해 살펴봐요 😀
이니셜라이저는 클래스나 구조체 또는 열거형의 인스턴스를 사용하기 위한 초기 과정이다.
또한, 초기화가 완료된 인스턴스는 사용 후 소멸된다.
초기화 과정은 새로운 인스턴스를 사용할 준비를 하기 위해 저장 프로퍼티의 초깃값을 설정하는 등의 일을 한다.
이니셜라이저를 정의하면 초기화 과정을 직접 구현할 수 있다.
class SomeClass {
init() { ... }
}
struct SomeStruct {
init() { ... }
}
enum SomeEnum {
case someCase
init() {
// 열거형은 초기화할 때 반드시 case중 하나가 되어야 한다.
self = .someCase
}
}
구조체와 클래스의 인스턴스는 처음 생성할 때 옵셔널 저장 프로퍼티를 제외
모든 저장 프로퍼티에 초깃값
을 할당해야 한다.
// 이니셜라이저를 이용한 할당
struct Location {
var loaction: String
init() {
self.loaction = "KOREA"
}
}
// 프로퍼티에 직접 할당
struct Location {
var loaction: String = "KOREA"
}
// 옵셔널 프로퍼티
struct Location {
var loaction: String?
}
상수로 선언된 저장 프로퍼티는 인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며,
처음 할당된 이후로는 값을 변경할 수 없다.
class Person {
let name: String
init(name: String) {
self.name = name
}
}
let fezz = Person(name: "Fezz")
fezz.name = "yagom" // Error!!
구조체는 사용자 정의 이니셜라이저를 구현하지 않으면
프로퍼티의 이름으로 매개변수를 갖는 이니셜라이저인 맴버와이즈 이니셜라이저를 기본으로 제공한다.
클래스는 제공하지 않는다
struct Way {
var left: Int = 10
var right: Int = -5
}
let bothSide = Way(left: 20, right: 10)
// 기본값이 존재한다면 각각 지정할 수 있다.
let leftSide = Way(left: 5)
let rightSide = Way(right: 20)
값 타입인 구조체와 열거형은 코드의 중복을 파하기 위하여
이니셜라이저가 다른 이니셜라이저에게 일부 초기화를 위임하는
초기화 위임을 구현할 수 있다.
다만, 클래스는 상속을 지원하므로 초기화 위임을 할 수 없다.
하지만 클래스는 상속에 따른 지정/편의 이니셜라이저를 통해 비슷하게 동작할 수 있다.
이 부분은 다음 포스트에서 해보는 걸로 ~
값 타입에서 이니셜라이저가 다른 이니셜라이저를 호출하려면 self.init
을 사용한다.
사용자 정의 이니셜라이저를 정의하면 기본 이니셜라이저와 맴버와이즈 이니셜라이저를 사용할 수 없다.
따라서 초기화 위힘을 하려면 최소 두 개 이상의 사용자 정의 이니셜라이저를 정의 해야 한다.
기본 이니셜라이저가 없어져서 속상하신가요? 😢
익스텐션을 사용하여 사용자 정의 이니셜라이저를 구현하면 됩니다.
enum RGBColor {
case red, green, blue
case white
case none
// 사용자 정의 이니셜라이저가 있는 경우,
// init() 메소드를 구현해야 기본 이니셜라이저를 사용할 수 있다.
init() {
self = .none
}
init(color: String) {
switch color {
case "red":
self = .red
case "green":
self = .green
case "blue":
self = .blue
case "redgereenblue"
self = .white
default:
self = .none
}
}
init(color: String, allSelect: Bool) {
self.init(color: allSelect == true ? "redgereenblue" : color)
}
var redPeople = RGBColor(color: "red")
var whitePeople = RGBColor(color: "red", allSelect: true)
}
예제를 만들다보니 점점 억지스럽게 됐는데...
아무튼 초기화를 위임 해줌으로써 코드를 중복으로 쓰지 않고도 효율적으로 여러 Case의 이니셜라이저를 만들 수 있다.
이니셜라이저를 통해 인스턴스를 초기화할 수 없는 여러 상황이 존재하는데,
대표적으로 이니셜라이저의 전달인자로 잘못된 값이나 적절치 못한 값이 전달되었을 때가 있다.
실패 가능한 이니셜라이저는 클래스, 구조체 열거형 등에 모두 정의할 수 있다.
실패 가능한 이니셜라이저는 실패했을때 nil
을 반환해주므로 반환 타입이 옵셔널이다.
사실 실패 가능한 이니셜라이저를 사용하지 않아도 적절하지 않는 값을 받아서
따로 오류처리가 가능하지만 좀더 간결하게 처리할 수 있다는 장점이 있는거 같다.
enum RGBColor: String {
case red = "빨강"
case green = "초록"
case blue = "파랑"
case white = "흰"
init?(color: String) {
switch color {
case "red":
self = .red
case "green":
self = .green
case "blue":
self = .blue
case "redgereenblue"
self = .white
default:
return nil
}
}
init?(color: String, allSelect: Bool) {
self.init(color: allSelect == true ? "redgereenblue" : color)
}
var people1 = RGBColor(color: "pink") // nil
var people2 = RGBColor(color: "orange", allSelect: false) // nil
var people3 = RGBColor(rawValue: "BlackPink") // nil
var people4 = RGBColor(rawVlue: "white") // white
}
점점 이상해지는 예제를 실패 가능한 이니셜라이저 예제로 활용해 봤습니다 !
적절하지 못한 값으로 이니셜라이저를 호출하게되면 nil
이 반환된다.
클래스의 인스턴스는 디이니셜라이져(Deinitializer)를 구현할 수 있다.
디이니셜라이저는 이니셜라이저와 반대의 역할는 하는데,
메모리에서 해제되기 직전 클래스 인스턴스와 관련하여 정리 작업을 할 수 있다.
디이니셜라이저는 클래스의 인스턴스에만 구현할 수 있다.
class SomeClass {
deinit { ... }
}
var instance = SomeClass()
instance = nil
📄 참고
[도서] 스위프트 프로그래밍 3판 - 야곰