옵셔널(Optional)

BS_Lee·2025년 7월 8일

swift

목록 보기
13/21

옵셔널(Optional)이란?

간단하게 말해서 이거다.

Optional은 값이 있을 수도, 없을 수도 있는 타입이다.

Swift는 타입 안정성을 굉장히 중요하게 생각한다.
그래서 nil이라는 개념을 아무 변수에나 막 쓸 수 없다.

var name: String = nil       // 에러
var name: String? = nil      // 에러 안남

즉, nil을 쓸 수 있으려면 명시적으로 ?를 붙여서 옵셔널 타입이라고 선언해줘야 한다.


다른 언어에서는 어떻게 처리할까?

여기서 궁금한 게 하나 생긴다.
다른 언어들도 이런 옵셔널 개념이 있을까?

한번 비교해보자.

언어null 표현옵셔널 처리 방식
JavaScriptnull, undefined아무 변수나 null 가능
PythonNone역시 아무 변수나 None 가능
Javanull, Optional<T>옵셔널은 선택사항
Swiftnil, Optional<T>옵셔널 타입만 nil 가능

옵셔널이 아니면 nil을 절대 못 넣는다.


옵셔널 비교연산

var age: Int? = nil

if age == nil {
    print("age는 nil입니다")
}

물론 가능하다. == nil을 직접 비교하는 것도 된다.
하지만 Swift에서는 더 깔끔하고 안전한 방식인 **if let이나 guard let**을 권장한다.


if let vs guard let

옵셔널을 안전하게 꺼내 쓰는 대표적인 방식이 이 두 가지다.

if let

if let value = optional {
    // value 사용 가능
    print(value)
}
print(value) // 에러발생

조건이 true일 때만 실행된다.
하지만 블록 내부에서만 value를 쓸 수 있다는 단점이 있다.

guard let

guard let value = optional 
else {
	print(value)
    return
}
print(value)
// 여기부터는 value가 nil이 아닐경우  구분을 타게 되어이음

이건 다르다.
조건이 false일 때 탈출하기 때문에 이후 코드에서는 언래핑된 value를 계속 쓸 수 있다.
중첩 코드 없이 플랫하게 유지할 수 있어서 훨씬 가독성이 좋다.

비교 항목if letguard let
조건 실패 시 처리블록 실행 안됨else 블록 실행 후 탈출
바인딩된 값 사용 가능 범위if 블록 내부만 가능이후 전체 코드에서 사용 가능
코드 구조중첩되기 쉬움플랫하게 깔끔하게 유지됨

옵셔널 체이닝

foo.address?.firstLine

옵셔널 체이닝은
중간의 어떤 값이 nil이라도 에러가 나지 않고, 전체가 nil이 되도록 안전하게 처리하는 방식이다.

예를 들어 아래와 같은 중첩된 구조를 생각해보자.

if let address = foo.address {
    if let line = address.firstLine {
        print(line)
    }
}

이걸 한 줄로 줄이면 다음과 같은 코드로 정리 할 수 있다.

if let line = foo.address?.firstLine {
    print(line)
}

엄청 깔끔해진다.


여러 개를 한 번에 바인딩하려면?

옵셔널 바인딩은 하나씩만 하는 게 아니다.

if let address = foo.address,			// 중간 값 바인딩
   let firstLine = address.firstLine {	// 최종 값 바인딩
    print(firstLine)	// 최종 값 사용가능
    print(address)		// 중간 값 사용가능
}

이렇게 ,로 이어서 순차적으로 바인딩할 수 있다.
중간 값을 쓰고 싶다면 이 방식이 유용하다.
옵셔널 체이닝은 결과만 얻을 수 있지만, 바인딩은 중간 값까지 활용 가능하다.


옵셔널의 내부 구조?

사실 옵셔널은 enum이다.

// optional 내부 구조
enum Optional<Wrapped> {
    case none           // == nil
    case some(Wrapped)  // 값이 있을 때
}

그래서 이런 코드도 완전히 가능하다.

switch age {
case .none:
    print("Age is nil")
case let .some(value):
    print("Age is \(value)")
}

즉, 옵셔널도 그냥 열거형일 뿐이다.
다만 Swift가 너무 잘 숨겨줘서 그런 줄 몰랐던 거다.

옵셔널을 선언할 때, 자료형 뒤에 ?를 붙여주는데 이건 optional자료형으로 wrapping하는 거라고 보면 된다.


guard lastName == nil else { ... }는 무슨 의미?

여기서 궁금한 게 또 하나 생긴다.
조건에 부정을 넣는 것도 가능할까?

guard lastName == nil else {
	// lastName이 nil일 경우 실행
    return
}
// nil이 아니면 실행

이건 lastName이 nil이 아니면 return, 즉
nil일 경우에만 계속 진행하겠다는 의미다.

guard는 결국 false일 때 탈출하는 거니까
조건을 부정으로 써도 전혀 문제없다.


한 줄 정리

옵셔널은 값이 있을 수도 없을 수도 있는 Swift만의 안전한 타입 시스템이며,
옵셔널 바인딩(if let, guard let), 체이닝, nil 병합(??) 등 다양한 방식으로 다룰 수 있다.


마무리하며....

옵셔널..... 자주 쓰이는 방식이니 잘 알아둬야겠다.

0개의 댓글