GGURUPiOS

Swift 공식 문서 정리 - (16) Optional Chaining 본문

Swift/공식문서 정리 ( 문법 )

Swift 공식 문서 정리 - (16) Optional Chaining

꾸럽 2023. 4. 28. 15:44

Optional Chaining (?)

옵셔널 체이닝은 nil일 수도 있는 프로퍼티나 메소드, 그리고 서브스크립트에 질의를 하는 과정

만약 옵셔널이 프로퍼티나 메소드 혹은 서브스크립트에 대한 값을 갖고 있다면 그 값을 반환,

만약 값이 nil이면 nil을 반환 함

강제 언래핑의 대체로써의 옵셔널 체이닝

옵셔널 체이닝은 옵셔널 값 뒤에 물음표를 붙여서 표현 가능 함

강제 언래핑하기 위해서 뒤에 느낌표를 붙이는 것과 문법이 비슷한데

강제 언래핑 → 그 값이 없으면 런타임 에러

옵셔널 체이닝 → nil 반환

예제를 살펴보자

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

// 만약 john의 residence에 numberOfRooms 프로퍼티에 접근하기 위해 
// 느낌표를 이용해 강제 언래핑 하면 값이 없기 때문에 런타임 에러 발생

let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \\(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Prints "Unable to retrieve the number of rooms."

// 런타임 오류대신 else 구문이 실행 됨.

옵셔널 체이닝을 위한 모델 클래스 정의

옵셔널 체이닝을 프로퍼티, 메소드, 서브스크립트에서 사용 가능

여러 레벨로 사용할 수 있음

아래코드는 위의 Person,Residence 모델을 확장해 Room과 Address 클래스를 추가한 4가지 모델을 정의 함

Person 클래스는 전과 같음

class Person {
    var residence: Residence?
}
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        get {
            return rooms[i]
        }
        set {
            rooms[i] = newValue
        }
    }
    func printNumberOfRooms() {
        print("The number of rooms is \\(numberOfRooms)")
    }
    var address: Address?
}

Residence는 rooms라는 프로퍼티를 소유하고, 이 프로퍼티는 [Room]타입의 빈 배열로 초기화 됨.

Residence가 Room인스턴스의 배열을 소유 하고 있기 때문에 numberOfRooms 프로퍼티는

계산된 프로퍼티로 선언됨

rooms 배열의 Room 클래스는 이름 하나를 초기화 때 인자로 받는 간단한 클래스 임

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

마지막 클래스는 Address 이고, 이클래스는 3개의 String? 옵셔널 프로퍼티를 갖는다.

buildingName, buildingNumber, street

class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if let buildingNumber = buildingNumber, let street = street {
            return "\\(buildingNumber) \\(street)"
        } else if buildingName != nil {
            return buildingName
        } else {
            return nil
        }
    }
}

// Address 클래스는 메소드를 하나 지원 함.
// 이 메소드는 빌딩넘버와 스트릿을 확인해 값이 있으면 빌딩 넘버와 결합된 스트릿 값을 반환하고 없는 경우 nil 반환

모델 정의가 끝났습니다.

아래에서 옵셔널 체이닝 예제를 볼게요

옵셔널 체이닝을 통한 프로퍼티의 접근

let john = Person()
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \\(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Prints "Unable to retrieve the number of rooms."

위 경우 residence? 가 nil 이기 때문에 nil을 호출하게 됨. 옵셔널 체이닝을 값을 할당하는데 사용도 가능하다.

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress

// 옵셔널 체이닝을 값을 할당하는 데에 사용함

if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \\(johnsStreet).")
} else {
    print("Unable to retrieve the address.")
}

// // Prints "John's street name is Laurel Street."

체이닝에서 옵셔널 값을 반환하는 메소드

아래 예제와 같이 옵셔널 체이닝에서 반환 값이 있는 메소드를 호출할 수 있음

if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
    print("John's building identifier is \\(buildingIdentifier).")
}
// Prints "John's building identifier is The Larches."