옵셔널에 속해있는 nil
일지도 모르는 프로퍼티, 메서드, 서브스크립션 등을 가져오거나 호출할 때 사용할 수 있는 일련의 과정을 옵셔널 체이닝이라고 한다. 이는 옵셔널 바인딩을 사용하지 않고 옵셔널 값에 접근하기에 매우 유용한 수단이 된다.
struct Developer {
let name: String
}
struct Company {
let name: String
var developer: Developer?
}
var company = Company(name: "Gunter", developer: nil)
print(company.developer)
// nil
var developer = Developer(name: "Han")
var company = Company(name: "Gunter", developer: developer)
print(company.developer)
// Optional(__lldb_expr_587.Developer(name: "Han"))
여기서, 옵셔널한 developer
의 name
속성에 접근하려고 하면 당연히 에러가 발생한다. 이때 이를 회피하기 위해 ?
를 사용하거나 !
를 사용하여 옵셔널 체이닝을 구사할 수 있다.
print(company.developer.name)
// Error! Value of optional type 'Developer?' must be unwrapped to refer to member 'name' of wrapped base type 'Developer'....
print(company.developer?.name)
// Optional("Han")
print(company.developer!.name)
// "Han"
Swift는 런타임에 에러가 발생(throwing)할 경우, 감지(catching), 전파(propagating), 조작(manipulating)의 처리를 지원하는 헬퍼 클래스를 지원한다.
enum PhoneError: Error {
case unknown
case batteryLow(batteryLevel: Int)
}
throw PhoneError.batteryLow(batteryLevel: 20)
// Playground execution terminated: An error was thrown and was not caught:
// PhoneError
// batteryLow : 1 element
// - batteryLevel : 20
func checkPhoneBatteryStatus(batteryLevel: Int) throws -> String {
guard batteryLevel != -1 else { throw PhoneError.unknown }
guard batteryLevel > 20 else { throw
PhoneError.batteryLow(batteryLevel: 20)
}
return "배터리 상태가 정상입니다"
}
do {
try checkPhoneBatteryStatus(batteryLevel: -1)
} catch PhoneError.unknown {
print("알 수 없는 에러입니다.")
} catch PhoneError.batteryLow(let batteryLevel) {
print("배터리 전원 부족.. 남은 배터리: \(batteryLevel)%")
} catch {
print("그 외 오류 발생: \(error)")
}
// "알 수 없는 에러입니다."
do {
try checkPhoneBatteryStatus(batteryLevel: 19)
} catch PhoneError.unknown {
print("알 수 없는 에러입니다.")
} catch PhoneError.batteryLow(let batteryLevel) {
print("배터리 전원 부족.. 남은 배터리: \(batteryLevel)%")
} catch {
print("그 외 오류 발생: \(error)")
}
// "배터리 전원 부족.. 남은 배터리: 19%"
let status1 = try? checkPhoneBatteryStatus(batteryLevel: -1)
print(status1)
// nil
let status2 = try? checkPhoneBatteryStatus(batteryLevel: 30)
print(status2)
// Optional("배터리 상태가 정상입니다")
let status3 = try! checkPhoneBatteryStatus(batteryLevel: 30)
print(status3)
// "배터리 상태가 정상입니다"
let status4 = try! checkPhoneBatteryStatus(batteryLevel: -1)
print(status4)
// __lldb_expr_643/example.playground:38: Fatal error: 'try!' expression unexpectedly raised an error...