티스토리 뷰
옵셔널 체이닝은 프로퍼티, 메소드, 서브스크립트들에게 현재 nil 값을 가지고 있는 옵셔널 타입인지 묻는 과정입니다. 만약 값이 nil이라면, 프로퍼티, 메소드. 서브스크립트는 nil을 반환합니다. 여러개의 옵셔널도 체인처럼 차근차근 값이 옵셔널인지 질문해 나아갈 수 있습니다.(아래에서 자세히 설명) 그리고 체인은 만약에 체인에 연결된 값 중 하나라도 nil이 있다면 실패합니다.
강제 언래핑의 대안인 옵셔널 체이닝
nil 값이 아닌 정상적인 값이 들어가있을때를 기대하고 프로퍼티나 메소드 혹은 서브스크립트를 호출할 때 옵셔널 값 앞에 ?를 붙임으로서 옵셔널 체이닝 시킵니다. 이것은 !를 붙이는 것과 매우 유사한데. 옵셔널 값이 언래핑되어진 이후 가장 주요한 차이점은 옵셔널 체이닝은 옵셔널이 nil일 경우 실패하는 반면 강제 언래핑은 nil일 경우 런타임 에러를 발생시킨다는 것입니다.
옵셔널 체이닝이 nil 값을 호출할 수 있다는 사실을 반영하기 위해 옵셔널 체이닝 호출의 결과는 항상 옵셔널 값으로 돌아옵니다. 이 이 옵셔널 값을 사용하여 옵셔널 체이닝이 성공적이였는지(반환된 옵셔널은 값을 가지고 있습니다) 아니면 체인 사이에 nil값이 있어 성공하지 못했는지 확인할 수 있습니다.
구체적으로 옵셔널 체이닝의 결과는 예상한 리턴타입과 동일한 타입입니다. 옵셔널로 감싸져있다는 사실이 다릅니다. 예로 옵셔널 체이닝을 통해 반환된 Int 타입은 Int?로 반환될 것입니다.
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
예제를 보면 Person 클래스는 Residence 클래스 옵셔널 타입을 프로퍼티로 가지고 있습니다. 기본 초기자(이니셜라이저)가 초기값을 nil로 넣어줄 것이기 때문에 john 인스턴스의 residence 프로퍼티의 초기값은 nil입니다.
let roomCount = john.residence!.numberOfRooms
// 런타입 에러 발생
residence 에 값이 있다면 괜찮지만 값이 없는 nil이라면 에러를 발생시킵니다. 이에 대안으로 옵셔널체이닝을 사용하면 됩니다.
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."
numberOfRooms이 옵셔널이 아닌 Int라도 Int?로 반환되는 것을 주의해야 합니다.
옵셔널 체이닝을 통해 모델 클래스 정의하기
옵셔널 체이닝을 프로퍼티, 메소드, 서브스크립트에서 아래 단계의 프로퍼티로 내려가면서 사용할 수 있습니다.
옵셔널 체이닝을 통해 메소드 호출하기
func printNumberOfRooms() {
print("The number of rooms is \(numberOfRooms)")
}
위 메소드는 리턴타입이 없지만, 정확히는 Void 타입이 리턴되고 있는 형태고 마찬가지로 옵셔널 체이닝을 사용하면 리턴값은 Void?가 됩니다, 이를 이용하여 옵셔널 바인딩으로 메소드가 호출되었는지 분기점을 만들어 확인할 수 있습니다.
if john.residence?.printNumberOfRooms() != nil {
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
// Prints "It was not possible to print the number of rooms.
또한 nil인 프로퍼티 밑의 프로퍼티에 값을 넣어주려는 시도도 가능한데 이 또한 제대로 값이 들어간 상태인지 옵셔널 바인딩과 같이 이용해 확인할 수 있습니다.
if (john.residence?.address = someAddress) != nil {
print("It was possible to set the address.")
} else {
print("It was not possible to set the address.")
}
// Prints "It was not possible to set the address."
옵셔널 체이닝을 통해 서브스크립트 접근하기
if let firstRoomName = john.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// Prints "Unable to retrieve the first room name."
앞서 설명한 프로퍼티와 메소드와 마찬가지. 괄호나오기 전에 ?붙여주는 것만 주의해주면 됩니다.
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0] += 1
testScores["Brian"]?[0] = 72
// the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]
마지막 Brian의 경우 딕셔너리에 해당 값이 없기 때문에 실패합니다.
여러 단계의 체이닝
얻으려는 값이 이미 옵셔널이든 아니면 옵셔널 값이 아니든 반환되는 값은 일단 옵셔널 타입으로 래핑되서 온다는 것만 유의
'Swift Language Guide' 카테고리의 다른 글
타입 캐스팅 + 중첩 타입 (0) | 2020.11.24 |
---|---|
Error Handling(에러 핸들링) (0) | 2020.11.19 |
11. 상속 (0) | 2020.11.09 |
10. 서브스크립트 (0) | 2020.11.08 |
9. 메소드 (0) | 2020.11.06 |