옵셔널은 안전성을 높이기 위해 사용되는 개념입니다. 즉 nil을 사용할 수 있는 타입과 사용할 수 없는 타입으로 구분하고, 사용할 수 있는 타입을 가리켜 옵셔널 타입이라고 부릅니다.

여기서 말하는 nil이란 값이 없음을 의미하는 특수한 값입니다. 정수의 0이나 문자열의 ""와는 다른 말 그대로 순수하게 아무 값도 없다는 것을 의미합니다. nil은 실제 값으로는 처리할 수 없는, 무엇인가 문제가 발생했을 때 이를 의미하기 위해 사용됩니다.

앞서 사용했던 딕셔너리를 생각해봅시다. 잘못된 키를 입력했을 때 오류가 발생된다면 프로그램이 안정적이지 못할 것입니다. 하지만 결과값으로 공백을 반환한다면 사용자가 그 키에는 공백이 저장되어 있었다고 착각할 수 있지 때문에 좋은 방법은 아닙니다. 이런 상황에서 스위프트는 뭔가 문제가 있다는 사실을 알려주기 위해 nil을 사용합니다.

let capital = ["KR": "Seoul", "CN": "Beijing", "JP": "Tokyo"]
capital["ko"] = nil

이처럼 값을 처리하는 과정에서 문제가 있을 경우 오류 발생 대신 nil을 반환합니다. 하지만 모든 타입이 nil을 반환할 수 있는 것이 아니며 오직 옵셔널 타입만 nil을 반환할 수 있습니다. 즉 nil을 반환하려면 해당 값이 옵셔널 타입으로 정의되 어 있어야 합니다.

여기서 중요한 것은 "오류가 발생할 가능성"입니다. 오류가 발생할 가능성이 조금이라도 있다면 모두 옵셔널 타입으로 정의해야 합니다. 만약 문자열을 정수형으로 바꾼다고 생각해 봅시다.

Int(바꿀 문자열)
let num = Int("123")

이 경우에는 num에 123이 대입될 것입니다. 하지만 아래의 경우라면 어떨까요?

let num = Int("swift")

대부분 다른 프로그래밍 언어에서는 이 상황을 오류나 예외사항으로 처리합니다. 그러나 스위프트는 언어의 안정성을 위해 가급적 오류를 발생시키지 않으려고 노력합니다. 오류가 발생하면 실행 흐름이 중단되고 경우에 따라 앱의 동작이 멈추거나 꺼질 수 있습니다. 따라서 이런 실패 케이스에도 억지로 값을 반환하려고 합니다.

하지만 아무 값이나 반환할 수 없습니다. 특히 0을 반환해서는 안 될 것입니다. 이런 케이스에 정의된 값이 바로 "값이 없음" 을 나타내는 nil입니다.

그런데 스위프트에서는 nil의 사용에 제약이 있습니다. 일반 자료형에는 nil 값을 가질 수 없습니다. 문자열이나 정수 등은 일반 자료형이기 때문에 "값이 없음"을 뜻하는 nil을 저장할 수 없습니다.

함수에서도 마찬가지입니다. 함수는 반환 타입이 정해져 있기 때문에 항상 그 타입에 맞는 값을 반환해야 하는데, 처리 과정이 실패했을 경우 nil을 반환합니다. 하지만 일반 자료형에는 nil값을 할당할 수 없다는 특성 때문에 nil을 반환하면 오류가 발생합니다.

이때 사용하는 타입이 옵셔널 타입입니다. 옵셔널 타입이 가질 수 있는 값은 오직 두 가지 뿐입니다. nil이 아닌 값, nil값입니다. 오류가 발생했다면 nil이, 오류가 발생하지 않았다면 nil이 아닌 값이 반환됩니다.

결국 옵셔널 타입이란 반환하고자 하는 값을 옵셔널 객체로 다시 한번 감싼 형태입니다. 앞서 "123"을 숫자로 변환한 값을 반환하고자 할 때 123을 직접 반환하는 것이 아니라 옵셔널 타입으로 감싼 Optional(123)을 반환합니다.

Int("123") -> Optional(123)
Int("swift") -> nil

처리가 성공적일 경우 옵셔널로 둘러싸여 있는데 이를 옵셔널 래핑이라 합니다. 이렇게 받은 값은 옵셔널 언래핑을 통해 실제 값을 추출해서 사용할 수 있습니다.

1. 옵셔널 타입 선언과 정의

일반 자료형을 옵셔널 자료형으로 만드는 방법은 자료형 뒤에 물음표만 붙이면 됩니다. 다음 예제를 살펴보겠습니다.

// 옵셔널 Int 타입
var optInt: Int?

// 옵셔널 String 타입
var optStr: String?

// 옵셔널 Double 타입
var optDouble: Double?

// 옵셔널 Array 타입
var optArray: [String]?

// 옵셔널 Dictionary 타입
var optDic: Dictionary<String, String>?
var optDic2: [String: String]?

// 옵셔널 Class 타입
var optClass: AnyObject?

일반 자료형을 선언만 하고 초기화하지 않으면 아무것도 할당되지 않지만, 옵셔널 타입으로 자료형을 선언하면 자동으로 nil로 초기화됩니다. 옵셔널 타입으로 선언된 변수나 상수에 실제 값을 할당하는 방법은 일반 타입의 그것과 동일합니다.

다음은 옵셔널 타입의 변수와 상수에 값을 할당하는 방법입니다.

// 옵셔널 Int 타입
var optInt: Int?
optInt = 3

// 옵셔널 String 타입
var optStr: String?
optStr = "Swift"

// 옵셔널 Array 타입
var optArr: [String]?
optArr = ["C", "Java", "SmallTalk"]

// 옵셔널 Dictionary 타입
var optDic: Dictionary<String, String>?
optDic = ["국어": 94, "수학": 88, "영어": 96]

값을 대입할 때에는 옵셔널이 아닌 일반 변수처럼 생각하고 다루어도 무방합니다.

2. 옵셔널 값 처리