특정 변수나 상수에 '해당 값이 없을 수 있음'을 직관적으로 표현가능하고 값이 없음을 나타내는 nil을 안전하게 처리할 수 있도록 한다. 옵셔널이 없다면 nil을 처리하는 과정에서 런타임 에러(프로그램이 실행되는 동안에 발생하는 에러)를 발생시킬 것이다.
var 이름: String?
이름이 String으로 된 값을 가질 수도 있고, nil(없음)일 수도 있다는 뜻
var Box: String?
if let name = Box {
print("\(name)")
} else {
print("nil") // 결과값: nil
}
위와 같은 경우에는 Box에 String타입의 값이 없기 때문에 else구문이 실행된다.
어떨 때 사용해야하지?
해당 타입의 값이 없을 가능성이 있을 때이다. 예를 들어 네트워크 요청, 데이터베이스 쿼리 등 외부 데이터 소스에서 값을 가져올 때 없을 가능성에 대비하여 안전하게 처리한다.
nil
일 경우 런타임 에러가 발생할 수 있다. 따라서 확신할 수 있을 때만 사용한다.var name: String? = "혜정"
print(name!)
var 이름: String? = "혜정"
if let 언래핑 = 이름 {
print(언래핑)
} else {
print("이름이 없어요..")
}
var 이름: String?
let 언래핑이름 = 이름 ?? "몰라요" //nil일 경우 몰라요 출력
print(언래핑이름)
class 사람 {
var 이름: String
var 애완동물: 고양이?
init(이름: String, 애완동물: 고양이? = nil) {
self.이름 = 이름
self.애완동물 = 애완동물
}
}
class 고양이 {
var 이름: String
var 수염: String?
init(이름: String, 수염: String? = nil) {
self.이름 = 이름
self.수염 = 수염
}
}
let 사람과애완동물 = 사람(이름: "혜정", 애완동물: 고양이(이름: "야옹잉", 수염: "하얀색"))
let 사람만 = 사람(이름: "혜정")
// 옵셔널 체이닝을 사용하여 안전하게 접근
if let 고양이수염 = 사람과애완동물.애완동물?.수염 {
print("혜정이네 고양이의 수염색깔은 \(고양이수염)")
} else {
print("혜정이네 고양이는 수염이 없어요")
}
if let 고양이수염 = 사람만.애완동물?.수염 {
print("혜정이네 고양이의 수염색깔은 \(고양이수염)")
} else {
print("혜정이네 고양이는 수염이 없어요")
}
'사람과애완동물.애완동물?.수염' 은 애완동물이 있고 그 애완동물의 수염이 무슨 색인지 확인한다. nil일 경우 "수염이 없어요"를 출력한다.
'사람만.애완동물?.수염' 은 애완동물이 없기 때문에 nil에 해당하는 값을 출력한다.
암시적 언래핑 옵셔널(Implicitly Unwrapped Optional)
옵셔널 타입이지만 값을 사용할 때 자동으로 언래핑되는 특성을 가진다. 옵셔널 값이 항상 존재함을 확신할 때 사용해야한다
예를 들어 초기화 후 값이 변경되지 않는 경우, 디자인 상 항상 값이 존재하는 경우 (ex. IBOutlet), 초기 설정이 완료된 후 사용되는 경우
1) 초기화 후 값이 변경되지 않는 경우
class ViewController {
var data: String!
func viewDidLoad() {
super.viewDidLoad()
data = "데이터 초기화" // 초기화, 이 이후에 nil이 아닐 것이 확실해진다.
}
func displayData() {
print(data)
}
}
2) 디자인 상 항상 값이 존재 ex. IBOutlet
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
// UILabel! 이라고 암시적 옵셔널이 선언되었다. 스토리보드에 연결되므로(일부러 연결을 끊지 않는 이상)뷰가 로드된 후에는 nil이 아닐 것이 보장된다.
override func viewDidLoad() {
super.viewDidLoad()
label.text = "Hello, World!"
// 따라서 이 부분에서 label을 언래핑해주지 않아도 사용할 수 있는 것
}
}
음..1의 강제 옵셔널의 설명과 헷갈리는데?
둘다 값의 존재를 확신할 수 있을 때에만 사용하라는 느낌은 비슷하다. 그렇지 않으면 런타임에러를 일으키는 것도.
그러나 암시적 옵셔널 언래핑은 정의할 때 사용되어서 호출될 때는 자동으로 언래핑된다는 것, 강제 언래핑은 호출 시점에 사용되어 언래핑 된다는 것.
// 암시적 언래핑 옵셔널
var name: String! = "hj" // 선언할 때 해놓고 나아간다
// 값을 부를 때 그냥 일반 변수처럼 부른다.
print(name) // "hj"
// 값이 nil일 경우에는 런타임 에러
name = nil
// print(name) // 런타임 에러 발생: Unexpectedly found nil while implicitly unwrapping an Optional value
var name: String? = "hj"
// 강제 언래핑
print(name!) // "hj"
// 값이 nil일 경우에는 런타임 에러
name = nil
// print(name!) // 런타임 에러 발생: Unexpectedly found nil while unwrapping an Optional value