옵셔널 체이닝
nil일 수도 있는 프로퍼티나, 메소드 그리고 서브스크립트에 질의(query)를 하는 과정
- 만약 옵셔널이 프로퍼티나 메소드 혹은 서브스크립트에 대한 값을 갖고 있다면 그 값을 반환함
- 만약 값이 nil이라면 nil 반환
강제 언래핑의 대체로써의 옵셔널 체이닝
- 옵셔널 값 뒤에 물음표(?)를 붙여서 표현 가능
- 옵셔널을 사용할 수 있는 값에는 프로퍼티, 메소드 그리고 서비스크립트가 포함
- 옵셔널 값을 강제 언래핑하기 위해 뒤에 느낌표(!)를 붙이는 것과 유사
- 강제 언래핑을 했는데 만약 그 값이 없으면 런타임 에러 발생
- 옵셔널 체이닝을 사용하면 런타임 에러 대신 nil이 반환
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
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."
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \\(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// Prints "John's residence has 1 room(s)."
옵셔널 체이닝을 위한 모델 클래스 정의
- 한 단계가 아닌 여러 단계(multi-level optional chaining) 사용할 수 있음
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?
}
class Room {
let name: String
init(name: String) { self.name = name }
}
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
}
}
}
옵셔널 체이닝을 통한 프로퍼티의 접근
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."
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress
- john.residence?가 nil이기 때문에 address 할당은 실패함
- 할당도 할당받는 왼쪽 항이 nil이면 아예 오른쪽 항이 실행되지 않음
func createAddress() -> Address {
print("Function was called.")
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
return someAddress
}
john.residence?.address = createAddress()
옵셔널 체이닝을 통한 메소드 호출
func printNumberOfRooms() {
print("The number of rooms is \\(numberOfRooms)")
}
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."
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."
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse
if let firstRoomName = john.residence?[0].name {
print("The first room name is \\(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// Prints "The first room name is Living Room."
- 옵셔널 타입의 서브스크립트 접근
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]
체이닝의 다중 레벨 연결
- 옵셔널 체이닝의 상위 레벨 값이 옵셔널인 경우 현재 값이 옵셔널이 아니더라도 그 값은 옵셔널값이 됩니다.
- 옵셔널 체이닝의 상위 레벨 값이 옵셔널이고 현재 값이 옵셔널 이라고 해서 더 옵셔널하게 되진 않습니다.
- 옵셔널 체이닝을 통해 값을 검색하거나 메소드를 호출하면 몇 단계를 거치는지 상관없이 옵셔널을 반환합니다.
if let johnsStreet = john.residence?.address?.street {
print("John's street name is \\(johnsStreet).")
} else {
print("Unable to retrieve the address.")
}
// Prints "Unable to retrieve the address."
let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence?.address = johnsAddress
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."
if let beginsWithThe =
john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
if beginsWithThe {
print("John's building identifier begins with \\"The\\".")
} else {
print("John's building identifier does not begin with \\"The\\".")
}
}
// Prints "John's building identifier begins with "The"."
반응형
'⌨️ Language > swift' 카테고리의 다른 글
[Swift] 프로토콜 (0) | 2024.03.29 |
---|---|
[Swift] 에러 처리 (0) | 2024.03.28 |
[Swift] 초기화 (1) | 2024.03.25 |
[Swift] 상속 (0) | 2024.03.22 |
[Swift] 서브스크립트 (0) | 2024.03.22 |
댓글