[스위프트 프로그래밍-11장] 인스턴스 생성 및 소멸

sanghee·2021년 11월 9일
0
post-thumbnail

이 글은 스위프트 프로그래밍(3판, 야곰 지음)을 읽고 간단하게 정리한 글입니다. 책에 친절한 설명과 관련 예제 코드들이 있으므로 직접 사서 읽기를 추천합니다.

11.0 소개

인스턴스

객체지향 프로그래밍에서 컴퓨터 저장공간에서 할당된 실체를 의미한다.

11.1 인스턴스 생성

이니셜라이저를 정의하여 초깃값을 설정할 수 있다. 구조체의 경우 기본값이 지정되어 있지 않아도 프로퍼티에 맞는 기본 이니셜라이저를 자동으로 제공한다.

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")

11.1.3 옵셔널 프로퍼티 타입

값을 꼭 갖지 않아도 되는 저장 프로퍼티는 옵셔널 타입으로 선언하면 된다.이니셜라이저에서 해당 프로퍼티를 초기화하지 않으면 자동으로 nil이 할당된다.

11.1.4 상수 프로퍼티

인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없다.

class Person {
    let name: String
    
    init(name: String) {
        self.name = name
    }
}

let person = Person(name: "name")
person.name = "new name" // error!

11.1.5 구조체의 멤버와이즈 이니셜라이저

사용자 정의 이니셜라이저를 정의하지 않다면 기본값이 있다는 전제하에 기본 이니셜라이저를 사용할 수 있다. 클래스와 다르게 구조체는 멤버와이즈 이니셜라이저를 기본으로 제공한다.

struct Person {
    let name = "name"
}

let person = Person()
print(person.name)

11.1.6 초기화 위임

구조체의 초기화 위임

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

11.1.7 init?

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

11.1.8 함수를 사용한 프로퍼티 기본값 설정

클로저를 통해 연산을 하여 프로퍼티의 기본값 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

11.2 deinit

디이니셜라이저는 클래스의 인스턴스에만 구현할 수 있다. 클래스의 인스턴스는 참조 카운트가 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
profile
👩‍💻

0개의 댓글