Swift

옵셔널을 다루는 방법들

GREEN.1229 2022. 8. 8. 12:16

안녕하세요. 그린입니다🟢

이번 포스팅에서는 Swift에서 옵셔널을 다루는 방법들에 대해 소개하려 합니다🙌

 

우선 옵셔널 참 많이 들어보셨죠?

Swift를 익히면서 당연히 안들어볼 수 없었을테고요.

그럼 우선 아주 심플하게 프리뷰로 옵셔널이 뭔지 딱 간략하게 정의하고 가죠!

 

옵셔널(Optional)?

Swift 언어의 대표적인 하나의 특성은 안정성입니다.

런타임 시 에러가 날때 이 오류를 nil값을 반환해줍니다.

그 이유는 들어온 nil값을 캐치해 개발자가 코드내에서 처리할 수 있도록 하기 위함이죠.

그렇다면 이 nil값을 받을 수 있는 타입이 필요할거에요.

기본 자료형 타입들에서는 nil값을 받을 시 앱 크래쉬가 날거니까요.

그렇기 위해 옵셔널이 존재합니다.

즉 말 그대로 옵셔널하기에 "값이 있을수도 없을수도 있다"라는 것을 타입에 적용한거죠.

이 타입은 값을 받아올 수도 있고 없는 즉 nil 값이 들어올 수도 있다라는 거죠.

즉 이렇게 nil값이 들어오는 에러의 환경을 유발한다면 옵셔널 타입으로 지정되는것이 좋습니다.

아주 쉽게 옵셔널 타입으로 지정하기 위해선 아래와 같은 ?(물음표)를 붙여주면 됩니다.

var name: String? = nil
var age: Int? = 3

만약 선언만하고 값의 할당이 없다면 당연히 nil 값으로 초기화됩니다.

 

자 그럼 이제 오늘의 주제로 바로 들어가보죠!

 

옵셔널을 해제해야하는 이유

즉 옵셔널 타입이 사용되는곳에서는 옵셔널 값 자체를 가지고 바로 유의미한걸 해주지 않습니다.

즉 이 타입에서 옵셔널을 제거하여 값에 대해 추출해내야하죠.

nil 값일 수도 있고 정상적인 기본 자료형의 타입일 수도 있는 당연히 두가지중의 하나의 경우겠죠?

그 경우 nil일 경우 에러를 처리하도록 분기처리를 할 수 있으며 옵셔널을 해제했는데 기본 자료형의 값이 있는 경우는 그 값을 사용해주거나 할 수 있겠죠.

이렇기에 실제 옵셔널을 해제해주고 진짜 있는 그 값으로 어떤 로직을 태워줘야하기에 해제해줘야합니다.

 

옵셔널을 다루는 방법들

그럼 정말 이제 진짜 주제네요!

옵셔널을 다루는 방법들에는 크게 잡아 3가지로 나타낼 수 있습니다.

명시적이니 묵시적이니 이런 거추장 스러운거 빼고 실제 코드를 짜며 사용되는 방법들을 실전으로 봐보시죠!

 

Force Unwrapping (강제 추출)

가장 쉽지만 제일 지양해야할 방법중 하나입니다.

!(느낌표)를 붙여 강제로 옵셔널을 해제시켜주는 방법이죠.

아래와 같이 사용할 수 있습니다.

var givenName: String? = "Green"
var familyName: String = "Color" + givenName!

이렇게 아주 간단히 옵셔널을 강제로 해제하고 원하는 타입으로 사용할 수 있습니다.

그런데 왜 강제 옵셔널을 해제하는 이 편한 방법을 지양해야할까요?

그건 바로 이 예시를 보면 이해할 수 있습니다.

var givenName: String? = nil
var familyName: String = "Color" + givenName!

familyName은 옵셔널 타입이 아닙니다.

즉 기본 String 타입이죠.

그렇기에 당연히 nil에 대해 지원하지 않습니다.

그럼 저 위의 코드에서 familyName에 옵셔널을 강제 추출하고 나온 nil값을 붙여주려면 에러가 나게 됩니다⚠️

이렇듯 컴파일 단에서 캐치할 수 없는 부분이기에 런타임 시 에러가 나며 실제 앱 크래쉬를 유발하게 됩니다.

그렇기에 강제 추출은 대부분의 많은 앱 크래쉬의 주요 원인중 하나가 됩니다🥲

 

Optional Binding (옵셔널 바인딩)

위에서 강제 추출을 지양해야하는 이유에 대해 알아봤습니다.

그럼 강제 추출하지 않고 어떻게 해제 시켜서 쓸건데..?

라고 했을때 이 옵셔널 바인딩이 방법이 될 수 있겠어요.

iOS 개발자가 아니더라도 Swift를 한번쯤 공부해보신다면 모를 수 없는 부분이긴 할것 같습니다!

그렇기에 바로 어떻게 옵셔널 바인딩을 하는 방법이 있는지 코드로 보시죠.

var name: String? = "Green"

// if let 바인딩
if let name = name {
  // name으로 실행할 로직
} else {
  // 필요에 따라 name이 nil 값일때 처리할 로직 (없어도 무방)
}

guard let name = name else {
  // name이 nil 값일떄 처리할 로직 (필수)
}

while let name = name {
  // name으로 반복 실행할 로직
}

이렇게 크게 흔히 쓰는 세가지 방법이 있습니다.

특이점은 guard let의 경우는 바인딩이 되지 않을 경우 즉, nil 값이 들어올 경우 else 구문을 꼭 코딩해줘야합니다.

그리고 바인딩된 name을 가지고 사용할 수 있습니다.

그에 반면 if let, while let 바인딩의 경우 해당 블록 안에서만 바인딩된 값을 사용할 수 있죠.

 

Optional Chaning (옵셔널 체이닝)

이제 마지막 옵셔널 체이닝이 남았습니다.

체이닝이라는것 들어보셨나요?

익숙치 않아도 상관없습니다. 보면 바로 아실 수 있어요ㅎㅎ

옵셔널들이 연속적으로 파고 들어가야할때 체이닝을 이용하죠.

옵셔널 타입에 접근할때 강제 추출과는 다릅니다.

즉 해제를 시키는것이 아닌 옵셔널 바인딩과 같은 개념으로 옵셔널 한지 체크하고 추출하는것이죠.

옵셔널 체이닝은 강제 언래핑의 대체제로 사용됩니다.

옵셔널 값 뒤에 ?(물음표)를 붙여 표현이 가능하죠.

강제 추출은 값이 존재하지 않으면 런타임 에러가 발생하는 반면 체이닝은 nil을 반환해주죠.

코드로 그러면 바로 보시죠!

class Person {
  var name: Name?
}

class Name {
  var givenName = "Green"
  var firstName = "Color"
}

let green = Person()

// 강제 추출 시 에러 유발
let greenGivenName = green.name!.givenName

// 옵셔널 체이닝
let greenFirstName = green.name?.firstName

위와 같은 코드로 강제추출과 옵셔널 체이닝의 사용을 명확히 보여줍니다.

강제 추출 시에는 값이 주어지지 않았기에 에러를 발생시킵니다.

반면 옵셔널 체이닝을 통한다면 해당 값을 옵셔널로 보내주는것이죠.

즉 greenFirstName의 타입은 옵셔널한 값입니다!

이걸 마지막으로 아래와 같이 바인딩해서 사용할 수 있죠🙌

if let greenFirstName = green.name?.firstName {
  // greenFirstName을 통한 로직 처리
}

 

마무리

이렇게 Swift에서 옵셔널을 다룰 수 있는 방법들에 대해 알아봤습니다.

아주 기초적이긴 하지만 앱 크래쉬를 유발하지 않기 위해서 꼭 필요한 부분이라 생각해요🤔

모두 쉽게 쉽게 가보자구요!