본 Lecture Note는 yagom.net의 '스위프트 기초' 강의를 수강하고 작성하였습니다.

스위프트의 핵심인 옵셔널(Optional)에 대해 알아보겠습니다.

옵셔널

값이 있을수도, 없을수도 있음을 이르는 Swift의 타입입니다.

옵셔널의 표현

옵셔널은 아래와 같이 표현할 수 있습니다. 어떤 표현도 명확히 이해가 가능하므로 두번째에 명시된 축약형 표현을 더 많이 사용하고 있습니다. 물음표는 타입 이름 뒤에 띄어쓰기 없이 붙여 사용하여야 합니다.

let optionalValue: Optional<Int> = nil
let optionalValue: Int? = nil

옵셔널이 왜 필요할까요?

nil의 가능성을 명시적으로 표현해줄 수 있기 때문입니다.

  • 옵셔널의 존재로 인해 nil의 가능성을 문서화 하지 않아도 코드만으로 충분히 표현이 가능합니다.
    • 이는 문서와 주석 작성 시간을 절약해줍니다.
  • 전달 받은 값이 옵셔널이 아니라면 nil 체크를 하지 않더라도 안심하고 사용할 수 있습니다.
    • 이로 인해 효율적인 코딩이 가능합니다.
    • 예외 상황을 최소화하는 안전한 코딩이 가능합니다.

예시로 아래 두 함수를 보시겠습니다.

// someOptionalParam can be nil.
func someFunction(someOptionalParam: Int?) {
  // ...
}
// someParam must not be nil.
func someFunction(someParam: Int) {
  // ...
}

someFunction(someOptionalParam: nil)
someFunction(someParam: nil)	// 에러 발생!

위의 예시와 같이 옵셔널의 존재로 인해 컴파일 단계에서 에러 발생을 인지할 수 있습니다. 주석을 지운다고 해도 이후에 다른 프로그래머가 코드를 보더라도 전해 이해에 문제가 발생 소지가 없는 것이죠.

옵셔널은 어떻게 이루어져 있나요?

열거형(enum)과 제네릭(Generic)의 합작으로 이루어져 있습니다. 아래 코드를 보시면 명확하게 이해하실 수 있으실 것입니다.

enum Optional<Wrapped>: ExpressibleByNilLiteral { // 열거형이 기본 타입입니다.
  case none
  case some(Wrapped)
}

옵셔널 타입 선언에서 자주보이는 !, ?는 무엇인가요?

!

변수 또는 상수를 선언할 때 옵셔널 타입 뒤에 붙여 사용하는 느낌표 표현은 암시적 추출 옵셔널 (Implicitly Unwrapped Optional) 형식을 뜻합니다. 아래 예시를 보시겠습니다.

var optionalValue: Int! = 100

switch optionalValue {	// 옵셔널은 열거형으로 정의되어 있으므로 switch 구문으로 구분이 가능합니다.
case .none:
  print("This Optional variable is nil")
case .some(let value):
  print("Value is \(value)")
}

// 기존 변수처럼 사용이 가능합니다.
optionalValue = optionalValue + 1

// nil을 할당할 수 있습니다.
optionalValue = nil

// nil이 할당된 변수를 연산하고자 할 경우 잘못된 접근으로 인한 런타임 오류가 발생합니다.
optionalValue = optionalValue + 1

위의 예시와 같이 암시적 추출 옵셔널을 통해 선언된 변수는 연산에 활용하는 등 기존 변수처럼 사용이 가능합니다. nil이 할당 가능하지만, nil이 할당된 변수를 연산하고자하면 런타임 오류가 발생합니다.

?

일반적인 옵셔널 형식입니다. 암시적 추출 옵셔널과 마찬가지로 해당 타입이 들어있을 수도 있고, 없을 수도 있습니다. 위와 같은 예시를 다시 가져왔습니다.

var optionalValue: Int? = 100

switch optionalValue {	// 옵셔널은 열거형으로 정의되어 있으므로 switch 구문으로 구분이 가능합니다.
case .none:
  print("This Optional variable is nil")
case .some(let value):
  print("Value is \(value)")
}

// nil을 할당할 수 있습니다.
optionalValue = nil

// 기존 변수처럼 사용이 불가합니다. 옵셔널과 일반 값은 다른 타입이므로 연산이 불가능하기 때문입니다.
optionalValue = optionalValue + 1

물음표를 통해 선언된 옵셔널은 Wrapped 상태를 해제하지 않으면 일반 값과 다른 타입이므로 연산에 활용할 수 없습니다. 그렇다면 Wrapped 상태는 어떻게 해제할까요? 해당 내용은 다음 포스팅에서 다루겠습니다.

profile
합리적인 해법 찾기를 좋아합니다.

0개의 댓글