본문 바로가기
iOS/Swift

[iOS/Swift] Optional, Unwrapped!

by iosdevlime 2022. 10. 31.

앞서 살펴본 Optional이란 타입이란? 

 

1. 변수나 상수의 초기값 X

2. 나중에 초기값을 할당할 예정

 

위 2가지 경우, 호출 시 발생되는 컴파일러 오류를 방지하기 위해 사용되는 또 다른 데이터 타입입니다.

 


그렇다면,

 

이러한 Optional로 선언된 변수나 상수에 초기값을 할당하게 된다면 어떤식으로 호출이 될까요?

만약 <Wrapped> 된 값이라면, 어떻게 올바른 값으로 활용할 수 있을까요? 

 

이를 해소하기 위해 Optional에 대하여 조금 더 알아보도록 하겠습니다.

 

 

 


 

 

Unwrapping

[Unwrapping] : Optional 타입으로 포장된 변수와 상수의 선언(초기)값을 사용하는 방법

 

 

정의

  • 특정 옵셔널 타입의 선언문을 Print 구문으로 호출하거나 타입(type of:) 을 살펴보면..
    • Optional이란 키워드 내부에 선언값이 포함되어 있거나, 타입 자체가 < >으로 감싸져 보입니다.
  •  
var optioanlString: String? = "Hello"

print(optioanlString)
// Optional("Hello")

print(type(of: optioanlString))
// Optional<String>
// type of:() 타입을 알려주는 메서드

 

  • 이와 같은 선언(초기)값은 Optional 타입으로 <Wrapped> 되어 있다는 것을 의미하며,
  • 선언값을 사용하기 위해 래핑을 뜯어내는, Unwrapping 과정이 필요합니다. 


 

 

 

Unwrapping 방식

  • 언래핑(Unwrapping) 방식은 크게 2가지로 구분됩니다. 
    • 옵셔널로 감싸져 있는 래핑을 '강제로 뜯어내는' 강제 언래핑, 암시적 언래핑
    • 임시 변수나 상수에 할당하고, 조건식을 통해 값을 '유연하게 드러내는' 옵셔널 바인딩'

 

(옵셔널 바인딩과 유사하지만 조금 다른 '옵셔널 체이닝' 개념은 추후에 다루도록 하겠습니다)

 

 

 


 

 

강제 언래핑 (Forced Unwrappig Optional)

Optional 타입에 느낌표(!)를 두어 강제적으로 Optional Type을 부수다!

 

 

정의 및 활용법

  • 옵셔널 타입이 없는, '래핑된 값'을 사용하고 싶다면?
    • 매우 간단하게, ‘강제 언래핑’ 이란 개념을 이용할 수 있습니다.
  • 사용방법은 매우 간단합니다!
    • 옵셔널 이름 뒤에 느낌표(!)를 두어 Optional<Type> ➠ <Type>으로 바꿀 수 있습니다.
// name 뒤에 느낌표 (!)를 붙여, 강제로 Optional<Type>을 <Type>으로 바꿔준다.

var name: String? = "Lime"

let unwrappingName: String = name!
print(unwrappingName)
// "Lime"
// 강제로 값이 도출되었다!

 

 

 

강제 언래핑의 위험성

  • 사실, 강제 언래핑은 매우 위험하며 실무에선 쓰지 않는 것이 원칙입니다..
만약, 옵셔널로 감싸진 선언(초기)값이 있는지 없는지(nil) 확인하지 않고 강제 언래핑을 하게 된다면..

컴파일러는
“어? 옵셔널을 해제해줬더니 nil 값이잖아..?” 라는 오류를 뱉어냅니다.
“어? 옵셔널을 해제해줬더니 nil 값이잖아..?” 라는 오류를 뱉어냅니다.

 

 


 

 

암시적 언래핑 (Implicitly unwrapped optional)

마치 처음부터 옵셔널 타입이 아닌 것처럼, 이미 언래핑 된 것처럼!

 

 

정의 및 활용법

  • 별도의 언래핑을 해줄 필요가 없이, 이미 언래핑 된 것처럼 작동시키는 방식입니다.
    • 옵셔널 타입 선언 시, 타입 뒤에 기존처럼 물음표(?)가 아닌, 느낌표(!)를 붙여줍니다. 
    • 아, 이런게 있구나..’ 정도로만 알아두는 것이 좋습니다.
let name: String! = "Jason"
// 옵셔널 선언 시점, 타입 뒤에 느낌표 (!) 를 붙이면?

let nameCopy = name // <-- 여기서, nameCopy는 Optional 타입이다!
Print(nameCopy) 
// "jason" 호출 완료.

 

 

 

강제 언래핑 vs 암시적 언래핑 

  • 공통점이라 함은, 둘 다 nil값을 가질 수 있다는 것이며, nil값 유무를 확인을 하지 않는다는 점입니다.
    • IUO(암시적 언래핑) 또한 결국 ‘강제 언래핑’ 이므로, 되도록 사용하지 않아야 합니다.
  • 사용이 되는 사례 중 하나로..
    • 반드시 할당된 값이 존재할 때, 편의성을 위해 이미 언래핑 된 것으로 의도할 경우입니다.
      •  대표적인 사례는 interface builder에서 선언되는 ‘아울렛(IBOutlet)’입니다.
        (@IBOutlet var imageView: UIImageView!) 

 

 


 

 

옵셔널 바인딩 (Optional Binding)

안전하고, 권장되는 언래핑 방식

 

 

정의

  • 강제 언래핑 대신, 옵셔널 바인딩(Optioanl binding)을 이용하면 안전하게 선언값을 이용할 수 있습니다.
  • 조건문을 활용함으로서, 옵셔널에 할당된 값을 임시 변수 또는 상수에 할당을 해주는 방식입니다.

 

 

 

활용법

  • 옵셔널 바인딩의 순서는 다음과 같습니다.
1. 임의의 정의된 상수&변수 값에 옵셔널 표현식을 대입한다.
2. 옵셔널 표현식을 조건식을 통해 살펴본다.
 - 초기화 값이 있을 경우(nil이 아니다!) 정의된 상수&변수에 옵셔널을 언래핑 하고,
 - true를 반환초기화 값이 없을 경우(nil일 경우), false를 반환

3. 정의된 상수&변수에 해당 옵셔널 표현식 값을 적용한다.

 

 

 

if let

  • 가장 기본적으로 활용되는 옵셔널 바인딩 방식입니다.
    • 아래 예시를 통해 구체적으로 살펴보도록 하겠습니다.
더보기
var index: Int?  // nil

index = 3 // 초기값을 할당

var treeArray = ["Oak", "Pine", "Yew", "Birch"]

if let myValue = index {
    print(treeArray[myValue])
    
    // 기존 옵셔널 함수와 임시 상수의 타입은??
    print(type(of: index)) // Optional<Int>
    print(type(of: myValue)) // Int

} else {
    print("index does not contain a value")
}

// 결과는 3번째 index인 Birch 호출

 

 

 

guard let 

  • 표현식이 nil인지 평가하여 nil일 경우, 함수의 실행을 종료시킬 때 활용하는 옵셔널 바인딩입니다.
    • 말 그대로, guard(가드)의 역할을 수행하는 것으로 이해할 수 있습니다.
  • 기본 형태는 다음과 같습니다. 
    • 값이 nil일때, else 구문으로 빠져 실행되며, return 값을 통해 함수를 종료시킵니다.
    • 만약, nil이 아닐 경우 guard let 구문에서 빠져나와 옵셔널이 해제된 값으로 사용 가능합니다!
guard let myValue = optioanlValue else {
 // myValue 는 nil이다!
 return
} 
// myValue 는 nil이 아니야! 그러니,,

댓글