본문 바로가기
iOS/SWIFT

[Swift] Chapter 08. 옵셔널

by 원만사 2021. 10. 8.
반응형

옵셔널은 안전성(Safe)을 문법으로 담보하는 기능이다.

값이 '있을 수도, 없을 수도 있음'을 나타내는 표현이다. 이는 '변수나 상수 등에 꼭 값이 있다는 것을 보장할 수 없다. 즉, 변수 또는 상수의 값이 nil일 수도 있다'는 것을 의미한다. 옵셔널과 옵셔널이 아닌 값은 철저히 다른 타입으로 인식하기 때문에 컴파일할 때 바로 오류를 걸러낼 수 있다.

 

8.1 옵셔널 사용


옵셔널 변수 또는 상수가 아니면 nil을 할당할 수 없다. 변수 또는 상수에 값이 없을 때만 nil로 표현한다. 값이 없는 옵셔널 변수 또는 상수에 (강제로) 접근하려면 런타임 오류가 발생한다. nil은 옵셔널로 선언된 곳에만 사용될 수 있다. 옵셔널 변수 또는 상수 등은 데이터 타입 뒤에 물음표(?)를 붙여 표현해준다.

 

/*
	코드 8-2. 옵셔널 변수의 선언 및 nil 할당
*/

var myName: String? = "yagom"
print(myName)

myName = nil

print(myName)

 

옵셔널은 어떤 상황에 사용할까? 옵셔널 사용의 예로 우리가 만든 함수에 전달되는 전달인자의 값이 잘못된 값일 경우에 제대로 처리하지 못했음을 nil을 반환하여 표현하는 것을 들 수 있다. 또는, 매개변수를 굳이 넘기지 않아도 된다는 뜻으로 매개변수의 타입을 옵셔널로 정의할 수도 있다.

옵셔널은 열거형으로 구현되어 있다. 그렇기 때문에 옵셔널 변수는 switch 구문을 통해 값이 있고 없음을 확인할 수 있다.

 

/*
	코드 8-4. switch를 통한 옵셔널 값의 확인
*/

func checkOptionalValue(value optionalValue: Any?) {
    switch optionalValue {
    case .none:
        print("This Optional variable is nil")
    case .some(let value):
        print("Value is \(value)")
    }
}

var myName: String? = "yagom"
checkOptionalValue(value: myName) // Value is yagom

myName = nil
checkOptionalValue(value: myName) // This Optional variable is nil

 

8.2 옵셔널 추출


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

8.2.1 강제 추출

옵셔널 강제 추출(Forced Unwrapping) 방식은 옵셔널의 값을 추출하는 가장 간단하지만 가장 위험한 방법이다. 런타임 오류가 일어날 가능성이 가장 높기 때문이다. 옵셔널 값의 뒤에 느낌표(!)를 붙여주면 값을 강제로 추출하여 반환해준다. 만약 강제 추출 시 옵셔널에 값이 없다면, 즉 nil이라면 런타임 오류가 발생한다.

 

/*
	코드 8-6. 옵셔널 값의 강제 추출
*/

var myName: String? = "yagom"

// 옵셔널이 아닌 변수에는 옵셔널 값이 들어갈 수 없다. 추출해서 할당해주어야 한다.
var yagom: String = myName!

myName = nil
yagom = myName! // 런타임 오류

// if 구문 등 조건문을 이용해서 조금 더 안전하게 처리해볼 수 있다.
if myName != nil {
    print("My name is \(myName!)")
} else {
    print("myName == nil")
}

// myName == nil

런타임 오류의 가능성을 항상 내포하기 때문에 옵셔널 강제 추출 방식 사용은 지양해야 한다.

 

8.2.2 옵셔널 바인딩

옵셔널 바인딩은 옵셔널에 값이 있는지 확인할 때 사용한다. 만약 옵셔널에 값이 있다면 옵셔널에서 추출한 값을 일정 블록 안에서 사용할 수 있는 상수나 변수로 할당해서 옵셔널이 아닌 형태로 사용할 수 있도록 해준다. 옵셔널 바인딩은 if 또는 while 구문 등과 결합하여 사용한다.

 

/*
	코드 8-7. 옵셔널 바인딩을 사용한 옵셔널 값의 추출
*/

var myName: String? = "yagom"

// 옵셔널 바인딩을 통한 임시 상수 할당
if let name = myName {
    print("My name is \(name)")
} else {
    print("myName == nil")
}
// My name is yagom

// 옵셔널 바인딩을 통한 임시 변수 할당
if var name = myName {
    name = "wizplan" // 변수이므로 내부에서 변경 가능
    print("My name is \(name)")
} else {
    print("myName == nil")
}
// My name is wizplan

 

[코드 8-7]의 예제에서는 if 구문을 실행하는 블록 안쪽에서만 name이라는 임시 상수를 사용할 수 있다. 즉, if 블록 밖에서는 사용할 수 없고 else 블록에서도 사용할 수 없다.

옵셔널 바인딩을 통해 한 번에 여러 옵셔널의 값을 추출할 수도 있다. 쉼표(,)를 사용해 바인딩 할 옵셔널을 나열하면 된다. 단, 바인딩하려는 옵셔널 중 하나라도 값이 없다면 해당 블록 내부의 명령문은 실행되지 않는다.

 

/*
	코드 8-8. 옵셔널 바인딩을 사용한 여러 개의 옵셔널 값의 추출
*/

var myName: String? = "yagom"
var yourName: String? = nil

// friend에 바인딩이 되지 않으므로 실행되지 않는다.
if let name = myName, let friend = yourName {
    print("We are friend! \(name) & \(friend)")
}

yourName = "eric"

if let name = myName, let friend = yourName {
    print("We are friend! \(name) & \(friend)")
}
// We are friend! yagom & eric

 

8.2.3 암시적 추출 옵셔널

때때로 nil을 할당하고 싶지만, 옵셔널 바인딩으로 매번 값을 추출하기 귀찮거나 로직상 nil 때문에 런타임 오류가 발생하지 않을 것 같다는 확신이 들 때 nil을 할당해줄 수 있는 옵셔널이 아닌 변수나 상수가 있으면 좋을 것이다. 이때 사용하는 것이 바로 암시적 추출 옵셔널(Implicitly Unwrapped Optionals)이다. 타입 뒤에 느낌표(!)를 사용해주면 된다.

암시적 추출 옵셔널로 지정된 타입은 일반 값처럼 사용할 수 있으나, 여전히 옵셔널이기 때문에 nil도 할당해줄 수 있다. 그러나 nil이 할당되어 있을 때 접근을 시도하면 런타임 오류가 발생한다.

 

/*
	코드 8-9. 암시적 추출 옵셔널의 사용
*/

var myName: String! = "yagom"
print(myName) // yagom
myName = nil

// 암시적 추출 옵셔널도 옵셔널이므로 당연히 바인딩을 사용할 수 있다.
if let name = myName {
    print("My name is \(name)")
} else {
    print("myName == nil")
}
// myName == nil

myName.isEmpty  // 오류!!

옵셔널을 사용할 때는 옵셔널 바인딩, nil 병합 연산자를 비롯해 뒤에서 배울 옵셔널 체이닝 등의 방법을 사용하는 편이 훨씬 안전하다.

 

 

스위프트 프로그래밍: Swift 5 - 교보문고

객체지향, 함수형, 프로토콜 지향 패러다임까지 한 번에! | 스위프트를 제대로 이해하고 싶은 개발자를 위한 책스위프트는 iOS와 macOS용 애플리케이션 개발에 주로 사용하는 프로그래밍 언어입니

www.kyobobook.co.kr

 

반응형

'iOS > SWIFT' 카테고리의 다른 글

[Swift] Chapter 10. 프로퍼티와 메서드  (0) 2021.10.08
[Swift] Chapter 09. 구조체와 클래스  (0) 2021.10.08
[Swift] Chapter 07. 함수  (0) 2021.10.08
[Swift] Chapter 06. 흐름 제어  (0) 2021.10.08
[Swift] Chapter 05. 연산자  (0) 2021.10.08

댓글