옵셔널 추출(Optional Unwrapping)이란 옵셔널의 값을 사용하기 위해서 꺼내오는 것이다.
이떄 옵셔널 추출법은 크게 두가지로 나뉠 수있다.
옵셔널 바인딩은 옵셔널 값을 꺼내오는 방법중 하나이다.
옵셔널 바인딩은 nil 체크를 하는 동시에 안전하게 값을 추출할 수 있는 방식이다.
옵셔널을 생각할 때 위 그림처럼 생각하면 이해하기 편하다.
어떠한 메모리안에 공간에 42라는 값이 들어 있다고 생각하면 옵셔널은 값들을 보호해주는 보호막이 하나 씩 있다고 생각하면 된다. 옵셔널 타입과 암시적 추출 옵셔널 둘다 옵셔널 타입이기 때문에 둘다 열거형 타입으로 박스가 하나 쌓여져 있다고 생각하면 된다.
가운데 박스 안에는 42라는 값이 있고 오른쪽 박스는 nil 즉 값이 없는 상태를 표현한다고 상상해보자.
옵셔널 바인딩 방법은 이때 상자에다가 물어보는 것이다.
우리가 상자에다가 "값이 들어 있습니까? 안에 들어 있습니까?" 하고 물어보는 것이다.
만약 안에 값이 있으면 그 값을 꺼내오고 없으면 값을 꺼내지 않고 그냥 지나친다.
func printName(_ name: String) {
print(name)
}
var myName: String? = nil
printName(myName) // 오류발생
printName
함수를 위와 같이 정의해두고 옵셔널 타입이 아닌 String
타입을 전달 받게 만들어 놨다.
그러나 myName
라는 변수는 옵셔널 타입이다.
만약 이 옵셔널 타입을 가지고 함수로 전달하게 되면 옵셔널 타입은 일반 String
타입과 다른 타입이기 때문에 컴파일 오류가 발생하게 된다.
그래서 이때 우리는 if - let 방식으로 옵셔널 바인딩을 해줄 수 있다.
func printName(_ name: String) {
print(name)
}
var yourName: String! = nil
if let name: String = yourName {
printName(name)
} else {
print("yourName == nil")
}
위 코드에서 yourName
는 암시적 추출 옵셔널이기 때문에 값을 if let name: String = yourName
이런식으로 값을 꺼내올 수 있다.
그런데 name
이라는 상수는 if - let 구문 안에서만 사용이 가능하다.
myName = "yagom"
yourName = nil
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
//>> 실행결과 없음
또한 위 코드처럼 한번에 하나씩만 바인딩 할 수 있는 것이 아니라 한번에 여러 옵셔널 변수들를 바인딩 할 수 있다.
그러나 위 코드는 myName
yourName
둘다 모두 값이 있어야 실행되게 되는데 yourName
의 값이 nil이기 때문에 if - let 구문이 실행되지 않는다.
또 다른 방법으로 Force Wrapping 방법이 있다.
이 방식은 강제로 옵셔널 값을 추출하는 방식이다.
옵셔널 바인딩에서는 정중하게 값을 꺼내오는 방식과는 다르게 여기서는 옵셔널 보호막을 강제로
망치로 깨부신 다음에 가져온다고 상상하면 된다.
func printName(_ name: String) {
print(name)
}
var myName: String? = "CHOI"
printName(myName!) // CHOI
앞서 사용했었던 함수를 가지고 위 코드를 확인해보면 printName(myName!)
과 같이 myName
에 느낌표를 붙임으로써 옵셔널의 값을 강제로 꺼내와서 전달하게 되고 myName
변수의 옵셔널 물음표가 벗겨지게 되면서 안에 있었던 "CHOI" 라는 값이 전달되게 된다.
그래서 옵셔널 타입이 아닌 String
타입으로 값을 전달할 수 있게 된다.
이렇게 변수뒤에 느낌표를 붙이게 되면 옵셔널 타입을 안에 값을 강제로 추출한다고 생각하면 된다.
myName = nil
print(myName!) // 런타임 오류 발생
그러나 위와 같이 nil 값을 할당하게 되면 강제 추출 할 때 값이 들어있지 않기 때문에 런타임 오류가 발생한다.
func printName(_ name: String) {
print(name)
}
var yourName: String! = nil
printName(yourName) // 런타임 오류 발생
여기서 암시적 추출 방식 처음에 선언할 때 부터 앞선 과정을 가정하고 선언한다고 생각하면 된다.
그래서 뒤에 느낌표를 붙이지 않았지만 printName(yourName)
를 하여도 전달하는 과정에 알아서 느낌표를 붙여준거와 같은 효과를 보여주게 된다.
위 코드는 nil 값을 전달하기 때문에 런타임 오류가 발생하게 된다.
결론적으로 옵셔널 강제추출 방식은 그다지 추천되는 방법은 아니고 조금더 안전하게 값을 추출하기 위해서
옵셔널 바인딩이 추천된다.