본문 바로가기
🍎 iOS/DevNote

[Swift] 옵셔널(Optional) 개념 정리

by @Eddy 2023. 5. 21.
728x90

// 옵셔널 체이닝 개념이 일부 잘못 작성되어 5월 24일 부 수정되었습니다.

 

프로젝트 중 ?, ! , nil 또는 아래와 같은 여러 에러들로 처음 옵셔널을 접했었다.

당시에는 이 정체모를 것이 에러를 발생시키는 원흉이라 생각했었는데, 지금은 따로 막 찾아보지 않아도 이렇게 정리할 수 있게 되었다.

Optional Error

옵셔널에 관련 에러메세지
1. Provide a default value to avoid this warning
2. Force-unwrap the value to avoid this warning
3. Explicitly cast to 'Any' with 'as Any' to silence this warning
4. The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.

옵셔널(Optional)?!

옵셔널은 Swift의 대표적인 특징 중 하나로,

부적절한 값에 의해 App Crush가 발생하는 것을 방지하기 위해 고안된 개념이다.

즉, 안전하게 코딩하기 위한 안전장치같은 개념으로, 값이 있을수도 없을수도(nil) 있을 때 사용한다.

 

사람도 흔히 '거기 있을껄?'처럼 불확실할 때 물음표를 붙이고, '거기에 있어!'라고 확신할 때 느낌표를 붙이듯 옵셔널은 '정수야?'와 '정수야!'로 이해하면 좋을 것 같다. 아직 잘 모르겠다면 계속 읽어보다가 방금의 예시를 다시 확인하면 아~ 라고 생각하지 않을까 싶다.

(옵셔널은 모르고 사용하면 에러의 원흉처럼 보이기도 하지만)  알고보면 nil 여부를 확인해줌으로써 개발자의 실수를 줄이는 데 도움을 준다.

 

여기서 nil은 해당 타입 값의 부재(Absence of Value)를 의미하며, Int타입에 String타입값을 입력했을 때에도 nil이라고 표현된다.

즉 Int 타입 값이 부재(Absence of Value)한다는 의미이다.


옵셔널 표현방식

1. Optional(타입값)

2. Optional.some(타입값)

3. 타입값?

Apple이 권장하는 방식은 String?처럼 타입에 ?를 붙이는 방식이다.

 

옵셔널 구현

옵셔널은 열거형(enum), 제네릭(Generic), switch로 구현되어 있다.

아래 내부 구현 코드를 보면, some과 none 2개의 enum case로 구현되어있음을 확인할 수 있다.

public enum Optional<Wrapped>: ExpressibleByNilLiteral {
  case none
  case some(Wrapped)
  
// Optional("Eddy") == Optinal.some("Eddy") == String?("Eddy")

 

아래는 Optional을 임의로 구현해본 코드이다.

Optional(String) 구현하기

 

Optional Unwrapping 4가지 방법

하지만 Optional상태를 upwrapped해야만 사용할 수 있으며,

Swift에서 Optional을 unwrap할 수 있는 4가지 방법을 제공한다.

1.  Unconditional Unwrapping ( = Forced Unwrapping )
2. Optional Binding
3. 논리적으로 nil인지 확인 후, 강제추출
4. Nil-Coalescing Operator

 

  1. Unconditional Unwrapping ( = Forced Unwrapping, 강제 언래핑 ) 

Forced Unwrapping 예제

  • 옵셔널값 뒤에 !를 사용하는 방법
  • Optional의 인스턴스 값이 있다고 확신할 때만 사용.
  • nil값이 있더라도 Optional 값을 무조건 unwrap.
    • 발생 에러: The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.
  • 즉 String?을 강제언래핑하면, String과 같은 의미이므로 해당 타입 값의 부재(nil)에 주의해야 한다.
  • 예상치못한 오류가 발생할 수 있으므로 사실상 비권장되는 방법

 

  2. Optional Binding(옵셔널 바인딩)  

Optional Binding 예제

Optional Binding 3가지 방법 ( 주로 if let-, guard let-사용 )
1. if - let
2. guard let ~ else 
3. switch
  • if let으로 선언된 변수는 {}(클로저) 내부에서만 사용이 가능하고
  • guard let은 선언된 범위 내(클래스나 함수 전체)에서 사용 가능하다

 

 3. 논리적으로 nil인지 확인 후 강제추출 

Optional Chaining 예제

  • 비교연산자(==)를 사용해 Optional이 nil인지 논리적으로 확인하는 방법
  • nil이 아닐 때, 해당 변수(옵셔널)을 사용하기 위해서는 주로 Forced Unwrapping(강제 언래핑)을 사용한다.

 

  4. Nil-Coalescing Operator ( 닐 코어레싱 연산 )  

Nil-Coalescing Operator 예제

  • 옵셔널에 ??를 사용하는 방법
  • 옵셔널값이 nil일 때 '기본값(Default Value)를 제공한다.
  • Nil-Coalescing(??)에 Nil-Coalescing(??)을 연결할 수 있다.

 번외. Optional Chaining ( 옵셔널 체이닝 ) 

  • 옵셔널 체이닝은 옵셔널(?)을 연결한(chaining) 형태로, 상위 인스턴스가 옵셔널 타입이라면 결과도 옵셔널을 반환하는 것을 기본으로 한다.
  • 옵셔널을 wrapping한다는 느낌은 아니지만, 알아두면 좋을 것 같아 함께 정리했다.
  • 위의 print예시 처럼 Optional(human)과 name을 연결한 것이 그 예이다.
  • return타입이 없는 함수: optional의 영향을 받지 않고 실행할 수 있는데, 그 이유는 상위 인스턴스가 nil이면 함수가 실행될 수 없기 때문이다. 
  • return 타입이 있는 함수: 상위 인스턴스가 옵셔널로서 nil을 가질 가능성이 있다면, 옵셔널타입으로 반환하게 된다.

요약

  1. 옵셔널은 올바른 타입 값 입력 여부를 파악해 개발자가 안전한 코딩을 할 수 있게 만들어준다.
  2. 옵셔널은 enum, generic, switch로 구현되어있다.
  3. 옵셔널을 벗겨내는(Unwrapping) 방법에는 4가지가 있다.
    • Forced Unwrapping(강제 언래핑, !)
    • 옵셔널 바인딩(if let, guard let, switch)
    • 논리적으로 nil인지 확인 후, 강제추출
    • Nil-Coalescing Operator(닐 코어레싱, ??)
  4. 옵셔널을 연결한 형태의 '옵셔널 체이닝'
  5. 이해를 위한 예시: 정수야? 정수야!

 

참고자료

반응형

댓글