[Swift] Optional

2025. 2. 1. 17:55iOS

반응형

Swift의 **옵셔널(Optional)**은 값이 있을 수도 있고 없을 수도 있는 변수를 안전하게 처리할 수 있도록 도와주는 개념입니다. 이는 nil을 허용하는 타입을 의미하며, Swift에서 널 포인터(nil pointer) 에러를 방지하기 위한 중요한 기능입니다.


1. 옵셔널이 필요한 이유

Swift에서는 nil을 기본적으로 허용하지 않습니다.
예를 들어, 아래 코드는 컴파일 오류가 발생합니다.

var name: String = "Swift"
name = nil  // ❌ 오류 발생

Swift에서는 모든 변수는 반드시 값을 가져야 하며 nil을 허용하려면 명시적으로 옵셔널로 선언해야 합니다.


2. 옵셔널의 선언 방법

옵셔널은 변수 타입 뒤에 ?를 붙여 선언합니다.

var name: String? = "Swift"
name = nil  // ✅ 가능 (옵셔널이므로 nil 저장 가능)

이제 name 변수는 "Swift" 또는 nil을 가질 수 있습니다.


3. 옵셔널의 기본 동작

옵셔널 변수는 값이 없을 수도 있기 때문에, 값을 직접 사용할 수 없습니다.

var name: String? = "Swift"
// print(name.uppercased())  // ❌ 오류 발생

옵셔널을 사용하려면 **안전하게 값을 꺼내는 방법(옵셔널 바인딩, 강제 언래핑 등)**을 사용해야 합니다.


4. 옵셔널 값 꺼내기 (Unwrapping)

(1) 강제 언래핑 (!)

옵셔널 값이 nil이 아님을 확신할 때 !를 사용하여 강제 언래핑할 수 있습니다.

var name: String? = "Swift"
print(name!)  // ✅ "Swift"

하지만 값이 nil일 경우 런타임 오류가 발생하기 때문에, 강제 언래핑은 주의해서 사용해야 합니다.

var name: String? = nil
print(name!)  // ❌ 런타임 오류 (Unexpectedly found nil)

(2) 옵셔널 바인딩 (if let / guard let)

옵셔널 바인딩을 사용하면 nil 여부를 안전하게 체크한 후 값을 사용할 수 있습니다.

✅ if let 사용 (안전한 언래핑)

var name: String? = "Swift"

if let unwrappedName = name {
    print(unwrappedName)  // ✅ "Swift"
} else {
    print("name이 nil입니다.")
}

if let은 name이 nil이 아닐 경우 값을 unwrappedName에 할당하고 블록 내부에서 사용할 수 있도록 합니다.

✅ guard let 사용 (함수에서 조기 탈출)

func printName(_ name: String?) {
    guard let unwrappedName = name else {
        print("이름이 없습니다.")
        return
    }
    print("이름은 \(unwrappedName)입니다.")
}

printName("Swift")  // ✅ "이름은 Swift입니다."
printName(nil)      // ✅ "이름이 없습니다."

guard let은 nil일 경우 즉시 함수에서 빠져나가게(return) 하여 코드의 가독성을 높입니다.


5. 옵셔널의 기본값 설정

(1) ?? (Nil-Coalescing Operator, 기본값 제공)

옵셔널 값이 nil일 경우 기본값을 제공할 때 ?? 연산자를 사용합니다.

var name: String? = nil
print(name ?? "기본값")  // ✅ "기본값"

?? 연산자는 name이 nil이면 "기본값"을 사용합니다.


6. 옵셔널 체이닝 (?.)

옵셔널 체이닝을 사용하면 옵셔널 값이 있을 경우에만 메서드나 프로퍼티를 호출할 수 있습니다.

struct User {
    var name: String
    var address: String?
}

let user: User? = User(name: "Alice", address: "Seoul")

// 옵셔널 체이닝 사용
print(user?.address?.uppercased() ?? "주소 없음")  // ✅ "SEOUL"

옵셔널 체이닝을 사용하면 nil일 경우에도 안전하게 nil을 반환하며, 런타임 오류를 방지할 수 있습니다.


7. 암시적 옵셔널 (! 사용)

옵셔널 변수 선언 시 ? 대신 !를 사용하면 **"값이 항상 존재한다고 가정"**하며, 자동으로 언래핑됩니다.

var name: String! = "Swift"
print(name)  // ✅ "Swift"

하지만, nil이 들어가면 런타임 오류가 발생하기 때문에 사용 시 주의해야 합니다.

var name: String! = nil
print(name)  // ❌ 런타임 오류 발생

💡 권장 사항:
! 대신 ?를 사용하고 옵셔널 바인딩으로 처리하는 것이 안전합니다.


8. 옵셔널의 활용 사례

(1) 딕셔너리에서 값 찾기

딕셔너리에서 키를 찾을 때 반환값은 옵셔널이므로, 값이 없을 경우 nil이 됩니다.

let scores = ["Alice": 90, "Bob": 85]
print(scores["Alice"])  // ✅ Optional(90)
print(scores["Charlie"])  // ✅ nil

값을 안전하게 가져오려면 옵셔널 바인딩을 사용합니다.

if let aliceScore = scores["Alice"] {
    print("Alice의 점수는 \(aliceScore)점입니다.")  // ✅ 90점
}

(2) Int 변환 시 옵셔널 반환

문자열을 정수로 변환하는 Int() 함수는 옵셔널을 반환합니다.

let number = Int("123")  // ✅ Optional(123)
let invalidNumber = Int("ABC")  // ✅ nil

(3) 함수의 옵셔널 반환값

함수의 반환값이 없을 수도 있을 경우, 옵셔널을 반환합니다.

func findIndex(of number: Int, in array: [Int]) -> Int? {
    return array.firstIndex(of: number)
}

let numbers = [1, 2, 3, 4, 5]
print(findIndex(of: 3, in: numbers))  // ✅ Optional(2)
print(findIndex(of: 6, in: numbers))  // ✅ nil

9. 정리

개념설명

? 옵셔널 선언 (값이 없을 수도 있음)
! 강제 언래핑 (값이 nil이면 오류 발생)
if let 안전한 옵셔널 바인딩 (값이 있을 경우 실행)
guard let 조기 탈출을 위한 옵셔널 바인딩
?? 기본값 제공 (Nil-Coalescing)
?. 옵셔널 체이닝
! (암시적) 옵셔널이지만 항상 값이 있다고 가정

옵셔널은 Swift에서 nil로 인해 발생하는 런타임 오류를 방지하고, 안전한 프로그래밍을 가능하게 해주는 핵심 기능입니다. 🚀

반응형

'iOS' 카테고리의 다른 글

[iOS] Performance Trace란?  (0) 2025.02.01
[iOS] Core Data vs Realm  (0) 2025.02.01
[iOS] HTTPCookieStorage와 WKHTTPCookieStore 차이  (0) 2025.01.30
[iOS] 웹뷰(WebView)기반 앱 개발 시 주의할 점  (2) 2025.01.30
[iOS] SwiftUI와 Combine (2)  (0) 2025.01.28