Skip to content

Latest commit

Β 

History

History
233 lines (183 loc) Β· 8.08 KB

Optional Chaining.md

File metadata and controls

233 lines (183 loc) Β· 8.08 KB

Optional Chaining

  • Optional Chaining은 ν˜„μž¬ nil일 κ°€λŠ₯성이 μžˆλŠ” μ˜΅μ…”λ„ νƒ€μž…μ˜ ν”„λ‘œνΌν‹°, λ©”μ„œλ“œ, μ„œλΈŒ 슀크립트λ₯Ό μΏΌλ¦¬ν•˜κ³  ν˜ΈμΆœν•˜λŠ” ν”„λ‘œμ„ΈμŠ€
  • 값이 있으면 ν˜ΈμΆœμ— 성곡; 값이 nil이면 nil λ°˜ν™˜
  • μ—¬λŸ¬ 개의 쿼리λ₯Ό μ—°κ²°ν•  수 있으며, ν•˜λ‚˜λΌλ„ nil이면 전체 체인이 μ‹€νŒ¨ν•œλ‹€.

Optional Chaining as an Alternative to Forced Unwrapping

  • μ˜΅μ…”λ„ 체이닝은 κ°’ 뒀에 λ¬ΌμŒν‘œ(?)λ₯Ό λΆ™μ—¬μ„œ ν‘œν˜„ κ°€λŠ₯
  • μ˜΅μ…”λ„μ„ μ‚¬μš©ν•  수 μžˆλŠ” κ°’: ν”„λ‘œνΌν‹°, λ©”μ†Œλ“œ, μ„œλΈŒ 슀크립트
  • κ°•μ œ μ–Έλž˜ν•‘(! μ‚¬μš©)κ³Ό 문법 μœ μ‚¬
    • 차이점: 값이 μ—†μœΌλ©΄ κ°•μ œ μ–Έλž˜ν•‘μ€ λŸ°νƒ€μž„ μ—λŸ¬κ°€ λ°œμƒν•˜μ§€λ§Œ, μ˜΅μ…”λ„ 체이닝은 nil λ°˜ν™˜
  • μ˜΅μ…”λ„ 체이닝에 μ˜ν•΄ nil 값이 호좜될 수 있기 λŒ€λ¬Έμ— μ˜΅μ…”λ„ μ²΄μ΄λ‹μ˜ 값은 항상 μ˜΅μ…”λ„
    • μ˜΅μ…”λ„ 값을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” κ°’(ν”„λ‘œνΌν‹°, λ©”μ†Œλ“œ, μ„œλΈŒ 슀크립트)λ₯Ό ν˜ΈμΆœν•˜λ”λΌλ„ μ˜΅μ…”λ„ 체이닝에 μ˜ν•΄ μ˜΅μ…”λ„ κ°’μœΌλ‘œ λ°˜ν™˜
  • μ˜΅μ…”λ„ μ²΄μ΄λ‹μ˜ 호좜 κ²°κ³ΌλŠ” μ˜ˆμƒλ˜λŠ” λ°˜ν™˜ κ°’κ³Ό λ™μΌν•œ νƒ€μž…μ΄μ§€λ§Œ μ˜΅μ…”λ„λ‘œ λž˜ν•‘ν•¨
    • ex) μ˜ˆμƒλ˜λŠ” 결과둜 Int λ°˜ν™˜; μ˜΅μ…”λ„ 체이닝을 μ‚¬μš©ν•˜λ©΄ Int? λ°˜ν™˜

Defining Model Classes for Optional Chaining

  • μ˜΅μ…”λ„ 체이닝을 ν•œ 레벨이 μ•„λ‹Œ μ—¬λŸ¬ 레벨둜 μ‚¬μš©ν•  수 μžˆλ‹€. (multilevel optional chaining)
  • λ³΅μž‘ν•œ ꡬ쑰의 λͺ¨λΈμ—μ„œ ν•˜μœ„ ν”„λ‘œνΌν‹°μ— μ ‘κ·Όν•΄μ„œ 값이 μžˆλŠ”μ§€ 확인할 수 μžˆλ‹€.
    • 체인 쀑 ν•˜λ‚˜λΌλ„ nil을 λ°˜ν™˜ν•˜λ©΄ μ‹€νŒ¨ν•œλ‹€.
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
        }
    }
}
  • buildingNumber, street λ‘˜ λ‹€ 있으면 λ°˜ν™˜ μ‹€νŒ¨ν•˜λ©΄ buildingName λ°˜ν™˜, 이것도 μ‹€νŒ¨ν•˜λ©΄ nil λ°˜ν™˜

Accessing Properties Through Optional Chaining

  • κ°•μ œ μ–Έλž˜ν•‘μ˜ λŒ€μ•ˆμœΌλ‘œ μ˜΅μ…”λ„ 체이닝을 μ‚¬μš©ν•˜λ©΄, μ˜΅μ…”λ„ κ°’μ˜ 속성에 μ ‘κ·Όν•˜κ³  ν•΄λ‹Ή 속성이 접근이 성곡적인지 확인할 수 μžˆλ‹€.
  • μ˜΅μ…”λ„ 체이닝을 μ΄μš©ν•΄ ν”„λ‘œνΌν‹°μ— μ ‘κ·Όν•  수 μžˆλ‹€.
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 호좜
func createAddress() -> Address {
    print("Function was called.")

    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"

    return someAddress
}
john.residence?.address = createAddress()
  • μ‹€ν–‰ κ²°κ³Ό "Function was called.”가 좜λ ₯λ˜μ§€ μ•ŠμŒ β†’ λ©”μ†Œλ“œκ°€ μ•„μ˜ˆ μ‹€ν–‰λ˜μ§€ μ•Šμ•˜λ‹€.
    • john.residence?κ°€ nil이기 λ•Œλ¬Έμ— ν• λ‹Ή λΆˆκ°€λŠ₯

Calling Methods Through Optional Chaining

  • μ˜΅μ…”λ„ 체이닝을 μ‚¬μš©ν•΄ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.
  • λ©”μ†Œλ“œμ—μ„œ 리턴 값을 μ •μ˜ν•˜μ§€ μ•Šμ•„λ„ μž‘μ—… μˆ˜ν–‰ κ°€λŠ₯
func printNumberOfRooms() {
    print("The number of rooms is \(numberOfRooms)")
}
  • 리턴 값이 λͺ…μ‹œλ˜μ§€ μ•Šμ•˜μ§€λ§Œ μžλ™μœΌλ‘œ 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."
  • ν”„λ‘œνΌν‹°λ₯Ό μ„ΈνŒ…ν•˜λŠ” 것도 λ‹€μŒκ³Ό 같은 λ°©μ‹μœΌλ‘œ 확인 κ°€λŠ₯

Accessing Subscripts Through Optional Chaining

  • μ˜΅μ…”λ„ 체이닝을 μ΄μš©ν•΄ μ˜΅μ…”λ„ 값을 μ„œλΈŒμŠ€ν¬λ¦½νŠΈλ‘œ μ ‘κ·Ό κ°€λŠ₯
  • μ„œλΈŒμŠ€ν¬λ¦½νŠΈμ˜ λŒ€κ΄„ν˜Έ μ•žμ— ?κ°€ λΆ™λŠ”λ‹€. (항상 μ˜΅μ…”λ„ ν‘œν˜„μ‹ λ°”λ‘œ 뒀에 ?κ°€ λΆ™λŠ”λ‹€.)
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."
  • 할당도 κ°€λŠ₯
john.residence?[0] = Room(name: "Bathroom")
// residenceκ°€ nil이라 μ‹€νŒ¨ 

Accessing Subscripts of Optional Type

μ„œλΈŒμŠ€ν¬λ¦½νŠΈκ°€ μ˜΅μ…”λ„ 값을 λ°˜ν™˜ν•˜λŠ” 경우(λ”•μ…”λ„ˆλ¦¬ νƒ€μž…) μ„œλΈŒ 슀크립트λ₯Ό λ‹«λŠ” λŒ€κ΄„ν˜Έ 뒀에 ?λ₯Ό μΆ”κ°€ν•˜μ—¬ μ˜΅μ…”λ„ 값을 μ—°κ²°ν•œλ‹€.

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]
  • λ”•μ…”λ„ˆλ¦¬κ°€ key 값을 잘λͺ» λ„£μ–΄μ„œ λ°˜ν™˜μ— μ‹€νŒ¨ν•΄λ„ 였λ₯˜κ°€ λ‚˜μ§€ μ•Šκ³  nil이 λ°˜ν™˜λœλ‹€.

Linking Multiple Levels of Chaining

  • μ˜΅μ…”λ„ 체이닝이 μ—¬λŸ¬ 단계에 걸쳐 연결될 수 μžˆλ‹€.
  • μ—¬λŸ¬ 단계가 겹쳐도 더 μ˜΅μ…”λ„ν•΄μ§€μ§€λŠ” μ•ŠλŠ”λ‹€. (μƒμœ„ κ°’κ³Ό ν•˜μœ„ 값이 λ‹€ μ˜΅μ…”λ„μ΄λΌκ³  μ˜΅μ…”λ„+κ°€ λ˜μ§€ μ•ŠλŠ”λ‹€.)

λ‹€λ₯Έ 말둜 ν•˜μžλ©΄

  • κ²€μƒ‰ν•˜λ €λŠ” νƒ€μž…μ΄ μ˜΅μ…”λ„μ΄ μ•„λ‹Œ κ²½μš°μ—λ„ μ˜΅μ…”λ„ μ²΄μ΄λ‹μœΌλ‘œ μ˜΅μ…”λ„ νƒ€μž…μ΄ λœλ‹€.
  • κ²€μƒ‰ν•˜λ €λŠ” νƒ€μž…μ΄ 이미 μ˜΅μ…”λ„μΈ 경우 μ˜΅μ…”λ„ 체이닝 λ•Œλ¬Έμ— 더 μ‹¬ν•œ μ˜΅μ…”λ„μ΄ λ˜μ§€ μ•ŠλŠ”λ‹€.

λ”°λΌμ„œ

  • μ˜΅μ…”λ„ 체이닝을 톡해 Int 값을 κ²€μƒ‰ν•˜λ €κ³  ν•˜λ©΄ 체인 μˆ˜μ€€μ— 관계 없이 항상 Int?κ°€ λ°˜ν™˜λœλ‹€.
  • λ§ˆμ°¬κ°€μ§€λ‘œ μ˜΅μ…”λ„ 체이닝을 톡해 Int? 값을 κ²€μƒ‰ν•˜λ €κ³  ν•˜λ©΄ μ—¬λŸ¬ 단계에 상관없이 Int?κ°€ λ°˜ν™˜λœλ‹€.
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse

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."
  • 2λ‹¨κ³„μ˜ μ˜΅μ…”λ„ μ²΄μ΄λ‹μœΌλ‘œ μ—°κ²°λ˜μ–΄ μžˆλ‹€.
  • residence?λŠ” μœ νš¨ν•˜μ§€λ§Œ address?의 값이 nilμ΄λ―€λ‘œ μ˜΅μ…”λ„ 체이닝은 μ‹€νŒ¨ν•œλ‹€.
  • μ˜΅μ…”λ„ 체이닝이 성곡할 경우, streetλŠ” String? νƒ€μž…μ˜ 값을 λ°˜ν™˜ν•œλ‹€.

Chaining on Methods with Optional Return Values

  • μ˜΅μ…”λ„ μ²΄μ΄λ‹μ—μ„œ λ°˜ν™˜ 값이 μžˆλŠ” λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆλ‹€.
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
    print("John's building identifier is \(buildingIdentifier).")
}
// Prints "John's building identifier is The Larches."
  • buildingIdentifier()의 λ°˜ν™˜ 값은 String?이닀
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 doesn't begin with \"The\".")
    }
}
// Prints "John's building identifier begins with "The"."
  • λ‹€μŒκ³Ό 같이 λ©”μ†Œλ“œμ˜ λ°˜ν™˜ 값에 μ˜΅μ…”λ„ 체이닝 ν•  수 μžˆλ‹€.