Swift에서 값이 없음(실제 값이 없는 것은 아님)을 나타내기 위해 사용한 방법이 Optional입니다.
nil(값없음)이 발생할 가능성이 있는 값을 임시타입(Optional)으로 감싸 사용하는 개념입니다.
nil은 값이 없다는 것을 의미하는 것이지, 실제 값이 없는 것은 아니다. (실제 값이 없으면 프로그램에 오류가 발생한다.) 즉, 메모리에 빈 저장공간이 할당된 상태를 의미하는 값입니다.
Swift는 안전성을 중요시하는 언어입니다.
값이 없는 상황 때문에 프로그램이 다운되는 것을 막고자 Optional을 활용하여 프로그램이 다운되는 불상사를 예방할 수 있습니다.
또한 일반적인 테이터 타입은 nil(값이 없음을 의미)을 할당할 수 없습니다. 하지만 Optional을 사용하면 nil을 사용/할당할 수 있습니다.
(즉 값이 있을 수도, 없을 수도 있는 상황을 표현하기 위해 Optional을 사용)
Optional(옵셔널)를 가장 간단하게 사용하는 방법으로는 변수(상수)의 타입 선언부 뒤에 "?" 또는 "!" 문자를 추가하여 사용하는 방법입니다. (변수명 뒤에 작성 X)
✅ 사용자에 의한 Optional(옵셔널) 선언
초기값이 없으면 nil값이 기본값으로 할당됩니다.
var hobby: String? var jobNum: Int! /* hobby = nil //할당받은 값이 없다. = 초기화 작업이 없었다. jobNum = nil */
초기값이 있으면 nil값이 아닌 옵셔널타입의 값이 할당됩니다.
var job: String? = "developer" var hobbyNum: Int! = 3 /* job = Optional("developer") hobbyNum = Optional(3) */
✅ 컴파일러에 의한 Optional(옵셔널) 선언
함수의 return 값이 없을 가능성이 있다면, 컴파일러에 의해 return 타입이 Optional(옵셔널) 타입으로 나올 수 있습니다.
함수 외에도 컴파일러가 판단했을 때 nil값이 나올 가능성이 있다 판단되는 경우에는 Optional(옵셔널) 타입으로 나올 수 있습니다.
var arr = [1,2,3,4,5] print(arr.max()) /* 출력 결과 Optional(5) */
이렇게 옵셔널 타입으로 저장/반환된 값들은 정상적인 연산을 할 수 없습니다. 그렇기 때문에 옵셔널을 벗기는 작업(unwrapping)을 진행한 뒤 사용해야 합니다.
옵셔널 타입의 데이터를 일반 타입의 데이터로 변경하는 과정을 옵셔널 언래핑(Optional Unwrapping)이라 부릅니다.
옵셔널을 벗기는 방법은 대표적으로 3가지가 존재합니다.
✅ 강제 언래핑(forced unwrapping)
강제 언래핑(forced unwrapping)은 값이 확실하게 존재한다고 생각할 때 사용하는 방법입니다.
만약 값이 없는 nil을 언래핑 할 경우 에러가 발생하기 때문에 확신이 들 때 사용해야 합니다.
var x: Int? = 10 print(x!) /* 출력 결과 10 */
✅ 옵셔널 바인딩(Optional Binding)⭐️
옵셔널 바인딩은 조건문을 활용하여 옵셔널 값을 벗겨내는 방법입니다. 조건식에서 새로 선언한 변수(상수)에 값을 저장할 수 있다면 true를 출력함과 동시에 값이 있다는 것을 증명하게 되므로 옵셔널을 벗겨낼 수 있습니다.
하지만 조건식의 결과가 false일 경우에는 값이 없다는 것을 의미하기 때문에 옵셔널 타입을 벗겨낼 수 없습니다. (값이 없음을 의미하는 nil을 unwrapping 할 경우 에러가 발생)
var x: Int? = 10 if let num = x{ print(num) } else{ print("nil") } /* 출력 결과 10 */
✅ 닐 코얼레싱 (Nil-Coalescing) 연산자
변수(상수)에 값을 할당받지 못할 경우를 대비하여 디폴트값을 미리 설정하여 사용하는 방식입니다.
디폴트값을 설정해 두면 변수(상수)에 nil이 저장될 경우가 없기 때문에 자동으로 옵셔널이 언래핑 됩니다.
- 값이 있으면 옵셔널 언래핑 하여 값 저장
var realName: String? = "김철수" var gameName = realName ?? "아무개" print(gameName) /* 출력 결과 김철수 */
- 값이 없으면 디폴트값 출력
var realName: String? var gameName = realName ?? "아무개" print(gameName) /* 출력 결과 아무개 */