이 글은 스위프트 프로그래밍(3판, 야곰 지음)을 읽고 간단하게 정리한 글입니다. 책에 친절한 설명과 관련 예제 코드들이 있으므로 직접 사서 읽기를 추천합니다.
객체지향 프로그래밍에서 컴퓨터 저장공간에서 할당된 실체를 의미한다.
이니셜라이저를 정의하여 초깃값을 설정할 수 있다. 구조체의 경우 기본값이 지정되어 있지 않아도 프로퍼티에 맞는 기본 이니셜라이저를 자동으로 제공한다.
struct Person {
let name: String
}
let person = Person(name: "name")
print(person.name)
이니셜라이저를 정의한 경우, 와일드카드 식별자(_)를 사용하여 전달인자 레이블을 생략할 수도 있다.
struct Person {
let name: String
init(_ name: String) {
self.name = name
}
}
let person = Person("name")
값을 꼭 갖지 않아도 되는 저장 프로퍼티는 옵셔널 타입으로 선언하면 된다.이니셜라이저에서 해당 프로퍼티를 초기화하지 않으면 자동으로 nil이 할당된다.
인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없다.
class Person {
let name: String
init(name: String) {
self.name = name
}
}
let person = Person(name: "name")
person.name = "new name" // error!
사용자 정의 이니셜라이저를 정의하지 않다면 기본값이 있다는 전제하에 기본 이니셜라이저를 사용할 수 있다. 클래스와 다르게 구조체는 멤버와이즈 이니셜라이저를 기본으로 제공한다.
struct Person {
let name = "name"
}
let person = Person()
print(person.name)
struct Person {
let age: Int
init(age: Int) {
self.age = age
}
init(lastYearAge: Int) {
self.init(age: lastYearAge + 1)
}
}
let person = Person(lastYearAge: 99)
print(person.age) // 100
convenience init은 보조 이니셜라이저로 원래 이니셜라이저인 init을 도와주는 역할이다. 사용하기 위해서는 init이 먼저 선언되어야 한다. 또한 convenience init 내부에서 반드시 designated init(지정 초기자, init)이 호출되어야 한다.
class Person {
let age: Int
init(age: Int) {
self.age = age
}
convenience init(lastYearAge: Int) {
self.init(age: lastYearAge + 1)
}
}
let person = Person(lastYearAge: 99)
print(person.age) // 100
Person은 age 프로퍼티를 가지고 있다. 하지만 나이는 0보다 작을 수 없다. 따라서 인스턴스를 생성할 때 age가 0보다 작은 경우에는 초기화하지 않는다.
class Person {
let age: Int
init?(age: Int) {
if age < 0 { return nil }
self.age = age
}
}
let person = Person(age: -1)
print(person) // nil
이러한 실패 가능한 이니셜라이저는 열거형에서 유효하게 사용될 수 있다. 해당 값이 어느 case에도 해당되지 않는 경우 nil을 리턴하면 되기 때문이다.
enum Student: String {
case elementary = "초등학생", middle = "중학생", high = "고등학생"
init?(age: Int) {
switch age {
case 8...13: self = .elementary
case 14...16: self = .middle
case 17...19: self = .high
default: return nil
}
}
}
let student = Student(age: 16)
print(student?.rawValue) // Optional("중학생")
let adult = Student(age: 20)
print(adult?.rawValue) // nil
클로저를 통해 연산을 하여 프로퍼티의 기본값 people을 설정하였다. 클로저 뒤에 소괄호 ()를 반드시 붙여야 한다(소괄호가 없다면 people은 클로저 그 자체가 되며 타입 오류가 발생한다).
struct Person {
let index: Int
}
class Room {
let people: [Person] = {
var arr: [Person] = []
for index in 1...10 {
arr.append(Person(index: index))
}
return arr
}()
}
let room = Room()
print(room.people.count) // 10
디이니셜라이저는 클래스의 인스턴스에만 구현할 수 있다. 클래스의 인스턴스는 참조 카운트가 0이 되면 자동으로 메모리에서 소멸된다. 소멸되기 직전에 호출된다.
class Room {
let name: String
init(_ name: String) {
self.name = name
}
deinit {
print("Room deinit")
}
}
var room: Room? = Room("name")
room = nil // Room deinit