[ Optional ]
옵셔널이란 값이 있을 수도 있고, 값이 없을 수도 있다는 것을 뜻한다.
let optionalValue: Optional<Int> = nil
let optionalValue: Int? = nil
Optional이 필요한 이유?
- nil의 가능성을 명시적으로 표현해줄 수 있기 때문이다. (nil의 가능성을 문서화 하지 않아도 코드만으로 충분히 표현 가능)
- 전달받은 값이 옵셔널이 아니라면 nil 체크를 하지 않더라도 안심하고 사용할 수 있다.
아래 예제와 같이 Int?(옵셔널) 타입이 명시된 함수에는 nil을 전달할 수 있지만 그렇지 않은 함수에는 nil을 전달할 수 없다.
Optional의 표현
- ! (Implicitly Unwrapped Optional, 암시적 추출 옵셔널)
// [ 암시적 추출 옵셔녈 ]
var optionalValue: Int! = 100
// Optional 타입 자체는 열거형이기 때문에 switch case문으로 구분해줄 수 있다.
switch optionalValue {
case .none: // 값이 없으면
print("This Optional variable is nil")
case .some(let value): // 값이 있으면
print("Value is \(value)")
}
/*
Value is 100
*/
// 기존 변수처럼 사용 가능
optionalValue = optionalValue + 1
// nil 할당 가능
optionalValue = nil
// But 잘못된 접근으로 인한 런타임 오류 발생 가능
optionalValue = optionalValue + 1
!로 표현된 옵셔널은 기존 변수처럼 사용하며 nil도 할당 가능하다.
하지만 nil이 할당된 채로 기존 변수처럼 사용하는 등의 잘못된 접근으로 인한 런타임 오류가 발생할 수 있다.
- ?
var optionalValue: Int? = 100
// Optional 타입 자체는 열거형이기 때문에 switch case문으로 구분해줄 수 있다.
switch optionalValue {
case .none: // 값이 없으면
print("This Optional variable is nil")
case .some(let value): // 값이 있으면
print("Value is \(value)")
}
// nil 할당 가능
optionalValue = nil
// 하지만 기존 변수처럼 사용은 불가 ==> 옵셔널과 일반 값은 다른 타입이므로 연산 불가
optionalValue = optionalValue + 1
?로 표현된 옵셔널은 nil 할당은 가능하지만 기존 변수처럼은 사용할 수 없다.
옵셔널 타입과 일반 타입을 확실하게 구분하여 잘못된 접근을 애초에 예방해준다.
그렇기 때문에 옵셔널 타입의 값은 다른 방식으로 추출하고 접근해주어야 한다.
[ 옵셔널 값 추출 - Optional Unwrapping ]
옵셔널 값을 추출하는 방법은 2가지가 있다.
1. Optional Binding - 옵셔널 바인딩
옵셔널의 값을 꺼내오는 방법 중 하나로
nil체크 + 안전한 값 추출 이 가능하다.
옵셔널 값을 꺼내오기 전에 한 번 물어보는 것처럼 생각하면 좋다. (값이 있으면 꺼내오고, 아니면 안꺼냄)
아래 코드에서는 String 타입의 매개변수를 받는 함수에 Optional 타입의 변수를 넣어준다.
String과 Optional은 다른 타입이기 때문에 오류가 발생한다.
func printName(_ name: String){
print(name)
}
var myName: String? = nil
printName(myName) // 전달되는 값의 타입이 다르기 때문에 컴파일 오류 발생
- if - let 방식
if-let 방식을 통해서 옵셔널 바인딩이 가능하다.
func printName(_ name: String){
print(name)
}
var myName: String! = nil
if let name: String = myName {
printName(name)
} else {
print("myName == nil")
}
// name 상수는 if-let 구문 내에서만 사용 가능
name 상수를 if-let 구문 밖에서 사용 시에는 컴파일 오류가 발생한다.
한번에 여러 옵셔널 변수들도 바인딩 가능하다.
var myName: String? = "kybeen"
var yourName: String? = nil
if let name = myName, let friend = yourName {
print("\(name) and \(friend)") // myName과 yourName 모두 값이 들어 있어야 실행
}
// yourName이 nil이기 때문에 실행되지 X
yourName = "YOU"
if let name = myName, let friend = yourName {
print("\(name) and \(friend)")
}
// kybeen and YOU
2. Force Unwrapping - 강제 추출
옵셔널의 값을 강제로 추출하는 방식.
옵셔널 값을 꺼내오기 전에 물어보지 않고, 강제로 꺼내는 방식이라고 생각하면 된다.
func printName(_ name: String) {
print(name)
}
var myName: String? = "kybeen"
printName(myName!) // !를 붙여주면 옵셔널 값이 강제로 추출돼서 전달
myName = nil
print(myName!)
// nil값이 들어있으면 강제추출 시 값이 없으므로 런타임 오류 발생
// 암시적 추출 옵셔널 방식은 선언할 때부터 위와 같은 상황을 염두에 두는 것임
var yourName: String! = nil
printName(yourName) // ! 안붙여줘도 된다. yourName은 nil값이기 때문에 런타임 오류 발생
오류 가능성이 있는 강제추출 방식 보다는 안전하고 확실한 방법인 옵셔널 바인딩을 사용하도록 하자!!!
- ! 말고 ?로 타입 명시
- if - let 구문 사용
'Swift' 카테고리의 다른 글
[ Swift ] Swift 기초 문법6 - 열거형 (0) | 2023.01.30 |
---|---|
[ Swift ] Swift 기초 문법5 - 구조체, 클래스 (0) | 2023.01.29 |
[ Swift ] Swift 기초 문법3 - 조건문, 반복문 (0) | 2023.01.28 |
[ Swift ] Swift 기초 문법2 - 함수 (0) | 2023.01.28 |
[ Swift ] Swift 기초 문법1 - 기본 데이터 타입 (1) | 2023.01.28 |