Optional 사용법

이원희·2021년 1월 4일
0

 🐧 Swift

목록 보기
4/32
post-thumbnail

오늘은 Optional의 사용법?이라기보단 Optional을 어떻게 벗기고 우리가 원하는 data로 사용할 수 있는지 그 방법에 대해서 알아보자.


Optional

우선 Optional에 대해서 간단하게 알아보자.
(자세한건 여기서 볼 수 있다.)

Optional은 값이 있을수도~ 없을수도~ 있는 경우에 사용한다.
값이 없다는 것은 nil을 의미한다.
Swift는 이런 Optional을 통해 프로그램의 안정성을 높인다.
Optional 타입임을 알리기 위해 타입 이름 뒤에 ?을 붙여서 표시한다.
Swift에서 Optionalnon-Optional 타입은 엄연히 다르게 취급된다.

그렇다면 우리는 Optional 타입인 어떤 프러퍼티에서 value를 가져다 사용하고 싶다.
어떻게 사용할 수 있는지 확인해보자.


Forced Unwrapping

Optional 값을 강제로 추출하려면 옵셔널 값 뒤에 !를 붙인다.
이 경우는 확실하게 Optional을 벗길 수 있지만 해당 프로퍼티에 값이 없다면 오류를 반환한다.

forcedUnwrapping!을 사용해서 강제 추출했다.
첫번째 print()에서는 forcedUnwrappingnil 값이 아니기 때문에 정상적으로 0이 출력되는 것을 확인할 수 있다.
두번째 print에서는 forcedUnwrappingnil 값이기 때문에 오류가 발생하는 것을 확인할 수 있다.

강제언래핑은 어떻게 구현되어 있을까?

public var unsafelyUnwrapped: Wrapped {
    get {
        if let x = self {
            return x
        }
        _debugPreconditionFailure("unsafelyUnwrapped of nil optional")
    }
}

if let을 사용해 self를 바인딩한다.
값이 있다면 반환하고 없다면 런타임에러를 발생시킨다.

var number: Int? = 3
number.unsafelyUnwrapped // 3
number = nil
number.unsafelyUnwrapped // 런타임 에러 발생
number! // number.unsafelyUnwrapped 와 같습니다.

직접 unsafelyUnwrapped를 호출할 수도 있다.


Optional Binding

옵셔널 바인딩은 if 혹은 guard문을 사용할 수 있다.

if를 사용한 옵셔널 바인딩은 값이 있는지 확인하고 해당 값을 임시 변수(상수)에 할당해서 사용하는 기법이다.
if문에서 생성한 임시 상수는 if문 내부에서만 사용할 수 있다.

guard를 사용한 옵셔널 바인딩은 guard문에 있는 조건이 false인 경우는 else로 진입하고, true인 경우에는 guard문 아래의 코드가 진행된다.
guard문으로 생성한 상수는 guard 구문 아래에서는 함수 내부의 지역 상수처럼 사용할 수 있다.
guard문의 else 안에는 return, break, continue, throw가 포함되어야 한다.
즉, guard문의 조건이 false인 경우는 더이상 아래의 코드를 실행하지 않는다.

Optional Binding에 대해서 더 궁금하다면 여기로!


Nil-Coalescing Operator

??을 사용한다.
값이 있는 경우는 옵셔널을 벗긴 값을 반환하고, 없는 경우에는 default 값을 설정할 수 있다.

binding 프로퍼티가 nil이 아닌 경우에는 프로퍼티의 value가 출력되고, nil인 경우에는 우리가 지정한 default 값이 출력되는 것을 확인할 수 있다.

??은 어떻게 구현되어 있을까?

public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
        rethrows -> T {
    switch optional {
    case .some(let value):
        return value
    case .none:
        return try defaultValue()
    }
}

optional 타입이 열거형으로 구현되어 있어 switch-case문으로 값이 있을 때와 없을 때를 나눠 구현한다.
연산자의 왼쪽에 위치할 인자에 값이 존재한다면 그 값을, 존재하지 않는다면 defatulValue 크로저를 실행해 기본값을 반환한다.

var number: Int? = 3
print(number ?? 0) // 3 출력
number = nil
print(number ?? 0) // number 의 값이 없으므로 기본값 0 출력

Optional Chaining

Optional Chaining의 결과는 항상 Optional이다.
Optional Chaining에 포함된 표현식 중 하나가 nil이라면 표현식을 중단하고 nil을 반환한다.

wonhee는 Optional 타입이 아니므로 name 프로퍼티에 접근시 ? 없이 접근 가능하다.
wonhee2는 Optional 타입으로 name 프로퍼티에 접근시 ?가 필요하다.
이때 옵셔널 체이닝했다고 한다.
옵셔널 체이닝의 결과는 항상 옵셔널이므로 두번째 출력도 Optional로 출력됨을 확인할 수 있다.

이번에는 Address라는 구조체를 만들고, Person에 Optional 타입을 갖는 address 프로퍼티를 정의했다.

위의 예제와 다른 점을 찾아보자면
wonhee에서 addresssi를 가져올 때 ?가 생겼다.
Person 구조체에 addressOptional 타입으로 선언되어 있어서 옵셔널 체이닝으로 가져와야 한다.
옵셔널 체이닝의 결과는 항상 옵셔널 이므로 출력 결과도 옵셔널이다.

wonhee2Optional 타입인 Person이므로 ?가 2개인 것을 확인할 수 있다.
옵셔널 체이닝시 포함된 표현식 중 하나가 nil이라면 표현식을 중단하고 nil을 반환한다고 했다.
wonhee2addressnil이므로 출력 결과가 nil이다.


마무리

오늘은 Optional을 어떻게 벗기는지 알아봤다.
방법은 여러 가지이고 각자의 특징과 결과가 다르니 이를 잘 알고 상황에 맞게 쓰는게 중요할거 같다.
그럼 이만👋

0개의 댓글