ex)
let num: Int? = 123
let num2: Int? = nil
값을 저장하고 싶지 않다면 옵셔널타입에 nil을 저장하면 된다. 그러나 놉옵셔널타입에 nil을 저장하면 에러가 발생한다. 논옵셔널타입이란 물음표키워드를 붙이지 않은, 지금까지 앞단원에서 사용했었던 모든 타입을 의미한다.
ex)
let str: String? = "Swift"
print(str!)
#####표현식 뒤에 느낌표를 붙이면 강제로 값이 추출이 된다. 그러나 nil을 저장한 후에 강제로 추출하면 어떻게 될까?
ex)
let str2: String? = nil
print(str!)
nil을 강제로 벗겨내는 것은 불가능하다. nil은 말그대로 값이 저장되어 있지 않다는 뜻으로 값이 없는 것을 강제로 추출하는 것은 불가능할 뿐더러 논리적으로도 말이 안된다. 그래서 강제로 추출하기 전에 항상 값이 저장되어 있는지 확인해야 한다.
ex)
if num != nil {
print(num!)
} else {
print("nil")
}
/* => 123
ex)
if let number = num {
print(number)
}
보통은 조건문에서 컨디션이 트루로 평가받아야 if블록 내부가 실행이 되었는데, 바인딩이 실행되는 조건은 좀 다르다. 옵셔널 표현식(let num: Int? = 123)을 평가하고 값이 리턴된다면 포장된 랩을 벗겨내서 상수에 저장한다. 이것이 바로 바인딩이 성공한 것이다. 그러면 컨디션이 트루로 평가되고, if블록 내부가 실행된다.
ex)
var say: String? = "Hello"
guard let say = say else {
fatalError()
}
print(say)
guard문에서의 옵셔널 사용은 혼동하기 쉽다. 바인딩한 상수는 else블록내에서 사용할 수 없다. else블록은 바인딩에 실패하였을때 실행되는 코드이다. 반드시 else블록 다음에서 사용이다가능하다.
ex)
let pen: String! = "Monami"
print(pen)
그러나 '암시적 추출 옵셔널' 역시 강제추출의 성격을 가지고 있기 때문에 크래쉬의 위험이 상당하다. 때문에 되도록이면 옵셔널바인딩을 하여 안전하게 추출하는 방법을 사용해야 한다.
ex)
let lastName: String? = nil
var naming = "My last name is" + (lastName ?? "X")
print(naming)
// => "My last name is X"
/* lastName에 nil이 저장되어 있기 떄문에 'X'가 반환된다.
ex)
class Idiya {
var americano: String
init(americano: String) {
self.americano = americano
}
}
class Dallcom {
var cappuccino: String
var idiya: Idiya?
init(cappuccino: String) {
self.cappuccino = cappuccino
}
}
var cafe = Dallcom(cappuccino: "카푸치노")
cafe.idiya?.americano
Dallcom 인스턴스를 생성하고 옵셔널체이닝으로 americano 속성에 접근했다.그러나 값이 존재하지 않기 떄문에 nil이 return 되었다.