저번에는 Optional에 대해서 알아봤었습니다. Optional을 모르시는 분은,
이 글을 통해 먼저 Optional이 무엇인지 알아보고 오시면 좋을 거 같네요 :)
옵셔널 바인딩(Optional Binding)이란?
Optional Binding은 Optional 타입으로 선언된 변수에 값이 있는지 없는지 확인할 수 있도록 도와주는 기능입니다.
Optional의 값이 존재하는지 검사한 후에, 값이 존재한다면 "!(느낌표)"를 사용하지 않고 Optional 타입의 변수 값을 출력할 수 있어서 조금 더 안전한 형태로 값을 얻을 수 있습니다.
'if let' 또는 'if var'를 사용하는데요. 옵셔널 값이 있다면 'if'구문이 실행되고, 값이 'nil'이라면 그냥 통과하게 됩니다.
글만으로는 부족하니, 아래 코드를 보면서 보도록 할게요 😋
if let name = optionalName {
print(name) // optionalName의 값이 존재하면 해당 값이 출력된다.
}
//
// optionalName의 값이 존재하지 않는다면, if문을 그냥 지나쳐서 이곳의 코드가 실행된다.
optionalName에 값이 존재한다면 name이라는 변수 안에 실제 값이 저장되고, if구문 내에서 그 값을 사용할 수 있게 됩니다. 하지만, optionalName의 값이 'nil'이라면 if문은 그냥 지나치게 됩니다.
아래의 코드처럼 하나의 if문에서 콤마(,)를 사용하여 여러 개의 옵셔널을 바인딩할 수 있으며, 콤마(,)가 &&(and)의 역할을 합니다.
var optionalName: String? = "홍길동"
var optionalCountry: String? = "Korea"
if let name = optionalName, country = optionalCountry {
// name과 country 값이 존재
}
// name과 country 값이 둘 중 하나라도 존재하지 않는 경우
또한 optional binding 이후, 그 값을 가지고 if와 같은 조건문도 같이 지정해줄 수 있습니다.
if let age = optionalAge {
if age >= 20 {
// age의 값이 존재하고, 20살 이상이다.
}
}
tip!! 코드가 많이 길어질 경우에는 아래와 같이 작성하여 가독성을 높이는 방법도 있습니다.
if let name = optionalName,
let country = optionalCountry {
// name과 country 값이 존재
}
// name과 country 값이 존재하지 않는 경우
옵셔널 체이닝(Optional Chaining)이란?
"Optional Chaining"은 이름에서 보이듯 체인처럼 이어진다는 느낌이라고 생각하시면 될 것 같은데요.
옵셔널 체이닝(Optional Chaining)은 하위의 property에 optional값이 있는지 없는지를 연속적으로 확인합니다. 만약, 중간에 하나라도 nil이 발견되면 그 즉시 'nil'이 반환되는 형식입니다.
또한, 옵셔널 체이닝의 속성은 일반적인 'Int'는 옵셔널 체이닝으로 접근할 때 'Int?'로 반환됩니다.
예제 코드를 보면서 설명을 하겠는데요, 아래 예제 코드는 [스위프트 언어 가이드 - Optional Chaining]에 나와있는 예제를 사용하였습니다.
처음으로, 'Person'과 'Residence'라는 두 개의 클래스를 정의합니다.
class Person {
var residence: Residence?
}
// 두 개의 클래스가 호출되고, residence 라는 변수가 Residence 클래스를 옵셔널의 형태로 상속받고있다.
class Residence {
var numberOfRooms = 1
}
// Residence 인스턴스는 기본 값 1을 가지는 numberOfRooms라는 Int형 속성을 하나 가지게 된다.
아래의 코드에서 Person 타입의 인스턴스를 Jud로 생성해 줍니다.
let Jud = Person()
Jud의 property로는 residence가 있는데요, residence변수는 Residence클래스를 옵셔널의 형태로 상속받고 있습니다.
옵셔널 타입은 따로 초기화해주지 않으면 nil로 초기화가 되기 때문에, 위의 코드의 Jud에서 residence 속성 값은 nil이 되겠네요.
let roomCount = Jud.residence!.numberOfRooms
// this triggers a runtime error
위의 코드를 보면 밑에 주석 부분과 같이 오류가 생성됩니다. 그 이유는 Jud에서의 residence 속성 값이 nil인데, '!'를 사용하여 Unwrap 하려고 하였기 때문입니다.
아래의 코드는 Jud.residence의 값이 nil이기 때문에, else문으로 넘어가서 코드가 실행되게 됩니다.
let roomCount = Jud.residence?.numberOfRooms {
print("Jud's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// 출력 결과 : "Unable to retrieve the number of rooms."
위의 에러가 났던 코드에서는 nil값을 '!'를 사용하여 Unwrap을 하려고 해서 오류가 났지만, 이번에는 '?'를 사용하여 강제 언래핑을 하지 않아서 오류는 생성되지 않습니다.
여기까지 사용해봤는데 어느 부분에 옵셔널 체이닝을 사용한 건지는 설명하지 않았네요? 어느 부분에서 옵셔널 체이닝을 사용했을까요? 🤔
let roomCount = Jud.residence?.numberOfRooms
바로 이 부분에 옵셔널 체이닝 방법을 적용하였습니다.
property를 통해 체인처럼 이어져있습니다. Jud.residence가 nil이 아니라면 numberOfRooms를 확인하여
roomCount 변수에 방 번호가 포함되어 저장되겠네요.
만일, 위의 코드가 if문의 조건을 수행하여 "Jud's residence has 1 room(s)."라는 결과가 나타나도록 하려면,
Jud.residence = Residence()
라는 코드를 추가하면 되겠네요.
Optional에 대해 포스팅할 때 설명했지만, 다시 한번 강조하자면 '!'를 사용하는 '강제 언래핑(Forced Unwrapping)'은 가능하면 사용하지 않는 것이 좋습니다.
그 이유와 '!(강제 언래핑)'을 언제 사용하는지가 궁금하다면, 위에 남겨둔 Optional 설명 글을 보시는 것을 추천드릴게요 👍
Optional Binding에 대한 설명은 여기까지입니다.
이 글을 읽으신 분들이 있다면 조금이나마 도움이 되길 바라며,
오타나 틀린 점이 있으면 지적해주시면 감사하겠습니다 👋
References
'📌 Swift' 카테고리의 다른 글
[오늘의 Swift 지식] In-Out이란 무엇일까? (0) | 2021.08.24 |
---|---|
[오늘의 Swift 지식] 전달인자(Argument)와 매개변수(Parameter) (0) | 2021.08.13 |
[오늘의 Swift 지식] if let과 guard let의 차이는? (0) | 2021.08.09 |
[오늘의 Swift 지식] 정렬 sort()와 sorted() (0) | 2021.07.17 |
[오늘의 Swift 지식] Optional이란? 🤔 (0) | 2021.07.11 |