👨🏻‍💻iOS 공부/Swift 기본기 다지기

[ETC_008] 옵셔널

728x90
반응형

옵셔널

옵셔널은 스위프트의 특징 중 하나인 안정성을 담보하는 기법이다.

옵셔널은 말 그대로 “있을 수도?,“없을 수도?”를 나타내는 표현이다. 즉 변수(var) 또는 상수(let)의 값이 nil(NULL)일 수 있다는 것이다.
(+ 옵셔널 변수/상수가 아니면 nil을 할당할 수 없다.)
즉, 변수 혹은 상수가 nil일 수 있으니 사용에 주의하라는 의미를 담고 있는 것이다.

nil을 할당하기 위해서는 “?”를 데이터 타입 뒤에 붙여줘야 한다.

var printName: String = "cha"

printName = nil

// nil cannot be assigned to type "String"

위 코드처럼 “?”를 붙이지 않으면 오류가 발생하게 된다.

var printName: String? = "cha"

printName = nil

// nil

앞의 코드에서 데이터 타입 뒤에 “?”를 붙여야 nil을 할당할 수 있게 된다.
조금 더 자세하게 쓰자면 아래와 같이 쓸 수 있다.

var name: Optional<String>

다만 “?”를 붙이는 것이 위의 방법보다 간단하고 직관적이다.

만약 매개변수가 옵셔널일 때는, 해당 매개변수에는 값이 없어도 된다는 것을 간파할 수 있어야 한다.

옵셔널 열거형의 정의를 보면, 값을 갖는 케이스와 아닌 케이스 두 가지로 나뉘어있다.
값을 가질 경우 연관값이 존재하는데, 이 때 옵셔널에 값이 있으면 해당 연관값에 할당이 된다. 즉 옵셔널이라는 열거형의 방패막에 보호되어 싸여있다는 것이다. 이 때 옵셔널의 값을 추출하는 법을 알아두어야 한다.

옵셔널 추출

열거형의 some 케이스로 숨어있는 옵셔널의 값을 옵셔널이 아닌 값으로 추출하는 옵셔널 추출(optional unwrapping) 방법에 대해 알아보자.

  • 강제 추출(Forced Unwrapping)

    해당 방식은 값을 추출하기 위한 가장 간단한 방법이지만, 그 만큼 가장 위험한 방법이다. (런타임 오류가 일어날 수 있기 때문이다)
    해당 방법으로 값을 추출하려면 옵셔널 값 뒤에 “!”를 붙여주면 된다. 강제 추출 시 옵셔널에 값이 없다면, 즉 nil이라면 런타임 오류를 발생시킨다.

    var soccer: String? = "Messi"

    var barcelona: String = soccer!


    soccer = nil

    barcelona = soccer!

    // Execution was interrupted

    런타임 오류의 가능성을 항상 갖고있기에, 강제 추출 방식은 지양해야한다.

  • 옵셔널 바인딩(Optional Binding)

    옵셔널 바인딩은 조금 더 세련된 방식에 해당된다. 옵셔널 바인딩은 옵셔널에 값이 있는지 확인할 때 사용하며, 값이 있다면 옵셔널에서 추출한 값을 일정 블록 안에서 사용할 수 있는 var이나 let으로 할당하여 옵셔널이 아닌 상태로 사용 가능하게 해준다. 옵셔널 바인딩은 if나 while 구문 등과 결합하여 사용 가능하다.

    if soccer != nil {

        print("\(soccer) is the best")

    } else {

        print("soccer == nil")

    }

    // nil일 경우 else문 실행


    var realLegend: String? = "guti"


    // 임시 상수 할당

    if let name = realLegend {

        print("\(name) is the legend")

    } else {

        print("--nil--")

    }

    // guti is the legend


    // 임시 변수 할당

    if var name = realLegend {

        name = "Kroos"

        print("\(name) is the legend")

    } else {

        print("--nil--")

    }

    // Kroos is the legend

    블록 안쪽에서만 name이라는 임시 상수를 사용할 수 있다. 그렇기에 모두 별도로 name을 사용하였지만, 충돌하지 않았다. 또한 상수로 사용하지 않고 var을 통해 임시 변수로 할당해도 된다.
    또한 옵셔널 바인딩을 통해 한 번에 여러 옵셔널의 값을 추출할 수 있다. 쉼표를 사용하여 바인딩 할 옵셔널의 값을 나열하면 된다. 다만 하나라도 값이 없다면 해당 블록 내부의 명령문은 실행되지 않는다!

    var arsenal: String? = "walcott"

    var chelsea: String? = nil

    var everton: String? = "arteta"


    if let london1 = arsenal, let london2 = chelsea {

        print("\(london1)\(london2)는 프리미어리그 선수였다.")

    }

    // 반환값 없음


    if let london1 = arsenal, let london2 = everton {

        print("\(london1)\(london2)는 프리미어리그 선수였다.")

    }

    // walcott과 arteta는 프리미어리그 선수였다.

    옵셔널 바인딩은 옵셔널 체이닝과 환상의 짝꿍이다. 이후 챕터에서 알아보자.

  • 암시적 추출 옵셔널

    암시적 추출 옵셔널로 지정하고 싶다면 ?가 아닌 !를 타입 뒤에 붙여주면 된다. 이는 일반값처럼 사용할 수 있으나, 여전히 옵셔널인 것은 변함이 없기에 nil값을 할당해 줄 수 있다. 다만 nil값이 할당되어 있다면, 런타임 오류가 발생한다.


옵셔널을 사용할 때에는 강제 추출, 암시적 추출 옵셔널보다는 옵셔널 바인딩과 체이닝을 사용하는 것이 가장 바람직하고 안전하다!

728x90
반응형