으니의 개발로그

[Swift] 옵셔널(1) - 옵셔널 사용 본문

Swift/책 정리

[Swift] 옵셔널(1) - 옵셔널 사용

아잉으니야 2021. 2. 1. 22:10

[Swift] 옵셔널(1) - 옵셔널 사용

이 글은 Swift 프로그래밍 책을 읽고 요약한 내용입니다.

 

옵셔널 : 값이 있을 수도 없을 수도 있음을 나타내는 표현

null 을 스위프트에서는 nil 로 표기함

 

  • 오류가 발생하는 nil 할당
import UIKit

var myName: String = "seonho"

myName = nil    // 오류

nil 은 옵셔널로 선언된 곳에서만 사용할 수 있다. 옵셔널 변수 또는 상수 등은 데이터 타입 뒤에 물음표(?)를 붙여 표현해준다.

 

var myName: String? = "seonho"
print(myName)
/* Optional("seonho") */

myName = nil
print(myName)
/* nil */

 

  • 옵셔널을 사용하는 상황
    • 함수에 전달되는 전달인자의 값이 잘못된 값일 경우 제대로 처리하지 못했음을 nil 을 반환하여 표현한다.
    • 매개변수를 굳이 넘기지 않아도 된다는 뜻으로 매개변수 타입을 옵셔널로 정의할 수 있다.

 

let primary = School(rawValue: "유치원")
let graduate = School(rawValue: "석박사")

let one = Numbers(rawValue: 1)
let three = Numbers(rawValue: 3)

위의 코드에서는 데이터 타입을 명시해주지 않고 타입 추론 기능을 사용했다. 왜냐하면 nil 을 할당하는 경우가 생기기 때문이다. 컴파일러는 아마도 primarygraduate 상수의 데이터 타입을 School? 이라고 추론했을 것이다. 또 onethree 상수의 데이터 타입은 Numbers 라고 추론했을 것이다. 이때 원시 값이 열거형의 case 에 해당하지 ㅇ낳으면 열거형 인스턴스 생성에 실패하여 nil 을 반환하는 경우가 생긴다. 앞에서 설명한 함수의 처리 실패 유형에 해당하는 것이다.

 

public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
    public init(_ some: Wrapped)
      /// 중략...
}

위의 코드에서 옵셔널은 제네릭이 적용된 열거형이다. ExpressibleByNilLiteral 프로토콜을 따른다는 것도 확인할 수 있다. 여기서는 옵셔널이 값을 갖는 케이스와 그렇지 못한 케이스 두 가지로 정이되어 있다. 즉, nil 일 때는 none 케이스가 될 것이고, 값이 있는 경우는 some 케이스가 되는데, 연관 값으로 Wrapped 가 있다. 따라서 옵셔널에 값이 있으면 some 의 연관 값인 Wrapped 에 값이 할당된다. 즉, 값이 옵셔널이라는 열거형의 방패막에 보호되어 래핑되어 있는 모습인 것이다.

 

옵셔널 자체가 열거형이기 때문에 옵셔널 변수는 switch 구문을 통해 값이 있고 없음을 확인할 수 있다.

func checkOptionalValue(value optionalValue: Any?) {
    switch optionalValue {
    case .none:
        print("This Optional variable is nil")
    case .some(let value):
        print("Value is \(value)")
    }
}

var myName: String? = "seonho"
checkOptionalValue(value: myName)
/* Value is seonho */

myName = nil
checkOptionalValue(value: myName)
/* This Optional variable is nil */

 

let numbers: [Int?] = [2, nil, -4, nil, 100]

for number in numbers {
    switch number {
    case .some(let value) where value < 0:
        print("Negative value!! \(value)")
    case .some(let value) where value > 10:
        print("Large value!! \(value)")

    case .some(let value):
        print("Value \(value)")

    case .none:
        print("nil")
    }
}

/*
 Value 2
 nil
 Negative value!! -4
 nil
 Large value!! 100
*/