본문 바로가기

모바일/스위프트

[Swift] 옵셔널(Optional)

옵셔널(Optional)

- 값이 있을수도 있고 없을 수도 있음을 나타냄

 

문자열 값이 있으면 "가나다" , 없으면 "" 일까?

""도 염연히 값이 있는 문자열이고 정확히는 값이 없는게 아니라 '빈 값'을 의미

값이 없는 문자열은 nil

 

정수형 값이 있으면 123 , 없으면 0일까?

마찬가지로 0은 0이라는 숫자이며 이 경우도 값이 없는 정수는 nil

 

빈 배열이나 빈 딕셔너리라고 해서 값이 없는게 아니라 '비어있을 뿐'

배열과 딕셔너리의 경우에도 '없는 값'은 nil

 

이렇게 값이 없는 경우에는 nil을 사용하고, 그렇다고 모든 변수에 nil을 넣을 수 있는 것은 아님

var name: String = "안녕하세요"
name = nil // 컴파일 에러!

 

값이 있을 수도 있고 없을 수도 있는 변수를 정의할 때에는 타입 어노테이션에 ?를 붙여야 함

이렇게 정의한 변수를 바로 옵셔널(Optional)이라고 함

옵셔널에 초깃값을 지정하지 않으면 기본값은 nil

 

var name: String?
print(name) // nil

name = "hoyhouse"
print(email) // Optional("hoyhouse")

 

옵셔널로 정의한 변수는 옵셔널이 아닌 변수와는 다름

let optionalEmail: String? = "hoyhouse@abc.com"
let requiredEmail: String = optionalEmail // 컴파일 에러 !

requiredEmail 변수는 옵셔널이 아닌 String 이기 때문에 항상 값을 가짐

optionalEmail은 옵셔널로 선언된 변수이기 때문에 실제 코드가 실행되기 전까지는 값이 있는지 없는지 알 수 없음

따라서 Swift 컴파일러는 안전을 위해 requiredEmail 에는 옵셔널로 선언된 변수를 대입할 수 없게 만듬

 

옵셔널 바인딩(Optional Binding)

옵셔널의 값을 가져오고 싶은 경우에 optional binding 사용

 

옵셔널 바인딩은 옵셔널의 값이 존재하는지를 검사한 뒤, 존재하면 그 값을 다른 변수에 대입

if let 또는 if var 사용

옵셔널의 값을 벗겨서 값이 있다면 if문 안으로 들어가고, 값이 nil이면 그냥 통과

 

optionalEmail에 값이 존재한다면 email 이라는 변수 안에 실제 값이 저장되고,

if 문 내에서 그 값을 사용 가능

optional이 nil이라면 if문이 실행되지 않고 넘어감

if let email = optionalEmail {
  print(email)
}

 

하나의 if문에서 콤마(,)로 구분하여 여러 옵셔널을 바인딩 가능

이곳에 사용된 모든 옵셔널의 값이 존재해야 if 문 안으로 진입

var optionalName: String? = "hoyhouse"
var optionalEmail: String? = "hoyhouse@abc.com"

if let name = optionalName, email = optionalEmail {
	// name과 email 값이 존재
}

 

코드가 길 경우 여러 줄에 걸쳐서 사용하는 것이 바람직

if let name = optionalName,
   let email = optionalEmail {
   // name 과 email 값이 존재
}

위 코드는 아래 코드와 동일

if let name = optionalName {
  if let email = optionalEmail {
    // name과 email 값이 존재
  }
}

 

옵셔널을 바인딩할 때 , 를 사용해서 조건을 함께 지정 가능

, 이후의 조건절은 옵셔널 바인딩이 일어난 후에 실행 -> 옵셔널이 벗겨진 값을 가지고 조건을 검사

var optionalAge: Int? = 22

if let age = optional, age >= 20 {
  // age의 값이 존재하고, 20 이상
}

위 코드는 아래 코드와 동일

if let age = optionalAge {
  if age >= 20 {
    // age의 값이 존재하고, 20 이상
  }
}

 

옵셔널 체이닝 (Optional Chaining)

Swift 코드를 간결하게 만들어주는 많은 요소 존재

옵셔널로 선언된 배열이 '빈 배열'인지 검사하기 위한 방법 -> nil이 아니면서 빈 배열인지 확인

let array: [String]? = []
var isEmptyArray = false

if let array = array, array.isEmpty {
  isEmptyArray = true
} else {
  isEmptyArray = false
}

isEmptyArray

 

옵셔널 체이닝 사용 시

let isEmptyArray = array?.isEmpty == true

 

옵셔널 체이닝은 옵셔널의 속성에 접근할 때, 옵셔널 바인딩 과정을 ? 키워드로 줄여주는 역할

array?.isEmpty

//array 가 nil인 경우 nil 반환
//array 가 빈 배열인 경우 true 반환
//array 에 요소가 있는 경우 false 반환

 

옵셔널 벗기기

옵셔널을 사용할 때마다 옵셔널 바인딩을 하는 것이 가장 바람직

하지만 개발을 하다보면 분명히 값이 존재함에도 옵셔널로 사용해야 하는 경우 존재

이럴 때에는 옵셔널에 값이 있다고 가정하고 값에 바로 접근할 수 있도록 도와주는 키워드인 ! 를 붙여서 사용

print(optionalEmail) // Optional("abd9757@abc.com")
print(optionalEmail!) // abd9757@abc.com

!를 사용할 때 옵셔널의 값이 nil인 경우에는 런타임 에러가 발생

Java의 NullPointerException과 비슷함

var optionalEmail: String?
print(optionalEmail!) //런타임 에러!

런타임 에러 발생 시 iOS 앱은 강제로 종료(크래시)

 

암묵적으로 벗겨진 옵셔널(Implicitly Unwrapped Optional)

옵셔널을 정의할 때 ? 대신 ! 를 붙이면 ImplicitlyUnwrappedOIptional 이라는 옵셔널로 정의

직역하면 '암묵적으로 벗겨진 옵셔널' 이라는 뜻

var email: String! = "abd9757@abc.com"
print(email) // abd9757@abc.com

이렇게 정의된 옵셔널은 nil을 포함할 수 있는 옵셔널이긴 한데, 접근할 때 옵셔널 바인딩이나 옵셔널을 벗기는 과정을

거치지 않고도 바로 값에 접근할 수 있다는 점에서 일반적인 옵셔널과 차이

 

옵셔널 벗기기와 마찬가지로, 값이 없는데 접근을 시도하면 런타임 에러 발생

var email: String!
print(email) // 런타임 에러!

 

가급적이면 일반적인 옵셔널을 사용해서 정의하고,

옵셔널 바인딩 또는 옵셔널 체이닝을 통해 값에 접근하는 것이 더 바람직

'모바일 > 스위프트' 카테고리의 다른 글

[Swift] 아웃렛 변수와 액션 함수 문법  (0) 2021.07.08
[Swift] Xcode 프로젝트 생성  (2) 2021.07.07
[Swift] 함수와 클로저  (0) 2021.07.07
[Swift] 조건문과 반복문  (0) 2021.07.05
[Swift] Swift란?  (0) 2021.07.05