[Swift] 이니셜라이저, 옵셔널 체이닝

최승원·2022년 5월 26일
0

TIL (Today I Learned)

목록 보기
16/21

이니셜라이저

class Person {
    var name: String
    var age: Int
    // 프로퍼티의 초기값이 꼭 필요 없는 경우에는 옵셔널을 사용
    var nickName: String?
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    // 자신의 이니셜라이저를 호출할 때는 convenience를 붙여야 함
    convenience init(name: String, age: Int, nickName: String) {
        self.init(name: name, age: age)
        self.nickName = nickName
    }
}

let hana: Person = Person(name: "hana", age: 20, nickName: "하나")
let jenny: Person = Person(name: "jenny", age: 10)

암시적 추출 optional property가 있는 경우

class Puppy {
    var name: String
    // 암시적 추출 옵셔널은 인스턴스 사용에 꼭 필요하지만
    // 초기값을 할당하지 않을 떄 사용
    var owner: Person!
    
    init(name: String) {
        self.name = name
    }
    
    func goOut() {
        print("\(name)가 주인 \(owner.name)와 산책을 합니다")
    }
}

// instance를 생성할 때 바로 초기값을 할당하지 않아도 됨
let happy: Puppy = Puppy(name: "happy")
happy.owner = jenny
happy.goOut() // happy가 주인 jenny와 산책을 합니다

실패 가능한 이니셜라이저

// 매개변수로 전달되는 값이 정상 범주가 아닐 경우 nil을 반환
class PersonB {
    var name: String
    var age: Int
    var nickName: String?
    
    init?(name: String, age: Int) {
        if(0...120).contains(age) == false {
            return nil
        }
        
        if name.count == 0 {
            return nil
        }
        
        self.name = name
        self.age = age
    }
}

// 실패 가능한 이니셜라이저는 optional로 선언해야 함
let john: PersonB? = PersonB(name: "john", age: 23)

deinit

// deinit은 클래스의 인스턴스가 메모리에서 해제되는 시점에 호출됨
class PersonE {
    var name: String
    var pet: Puppy?
    var child: Person
    
    init(name: String, child: Person) {
        self.name = name
        self.child = child
    }
    
    deinit {
        if let petName = pet?.name {
            print("\(name)\(child.name)에게 \(petName)를 물려줍니다")
            self.pet?.owner = child
        }
    }
}

var donald: PersonE? = PersonE(name: "donald", child: jenny)
donald?.pet = happy
donald = nil
// donald 인스턴스가 더 이상 필요 없으므로 메모리에서 해제됨
// donald가 jenny에게 happy를 물려줍니다

옵셔널 체이닝

// 구조체 안에 구조체가 있고, 그 구조체 안에 구조체가 또 있는 식으로
// 프로퍼티가 연속적으로 연결되는 경우
// 프로퍼티가 optional이면 항상 nil인지 아닌지 체크를 해야 한다.
// 이 떄 옵셔널 체이닝을 활용하면 코드가 간결해짐
class Person {
    var name: String
    var job: String?
    var home: Apartment?
    
    init(name: String) {
        self.name = name
    }
}

class Apartment {
    var buildingNumber: String
    var roomNumber: String
    var `guard`: Person?
    var owner: Person?
    
    init(dong: String, ho: String) {
        buildingNumber = dong
        roomNumber = ho
    }
}

let yagom: Person? = Person(name: "yagom")
let apart: Apartment? = Apartment(dong: "101", ho: "202")
let superman: Person? = Person(name: "superman")

// 만약에 옵셔널 체이닝을 사용하지 않는다면
func guardJob(owner: Person?) {
    if let owner = owner {
        if let home = owner.home {
            if let `guard` = home.guard {
                if let guardJob = `guard`.job {
                    print("우리집 경비원의 직업은 \(guardJob)입니다")
                } else {
                    print("우리집 경비원은 직업이 없어요")
                }
            }
        }
    }
}

// 옵셔널 체이닝을 사용한다면
func guardJobWithOptionalChianing(owner: Person?) {
    if let guardJob = owner?.home?.guard?.job {
        print("우리집 경비원의 직업은 \(guardJob)입니다")
    } else {
        print("우리집 경비원은 직업이 없어요")
    }
}

yagom?.home?.guard?.job // nil

yagom?.home = apart
yagom?.home // Optional(Apartment)
yagom?.home?.guard // nil

yagom?.home?.guard = superman
yagom?.home?.guard // Optional(Person)
yagom?.home?.guard?.name // superman
yagom?.home?.guard?.job // nil

yagom?.home?.guard?.job = "경비원"

nil 병합 연산자

// nil 병합 연산자
// 앞에 값이 nil이면 ?? 연산자 뒤의 값을 프로퍼티에 넣는다.
var guardJob: String
guardJob = yagom?.home?.guard?.job ?? "슈퍼맨"
print(guardJob) // 경비원

yagom?.home?.guard?.job = nil
guardJob = yagom?.home?.guard?.job ?? "슈퍼맨"
print(guardJob) // 슈퍼맨
profile
문의 사항은 메일로 부탁드립니다🙇‍♀️

0개의 댓글