이전에 옵셔널 체이닝에 대해서 다루었던 것이 기억난다.
옵셔널 체이닝은 옵셔널 내부의 내부의 내부로 옵셔널이 연결되어 있을 때 유용하게 활용할 수 있다.
매번 nil 을 확인하지 않아도 최종적으로 원하는 값이 있는지 없는지 확인할 수 있다.
이렇게 말하면 이해가 잘 되지 않으니 예제를 통해 알아봐야겠다.
옵셔널 체이닝 | Optional Chaining
우선, 두 개의 클래스를 만들었다.
class Person {
var name: String
var job: String?
var home: Apartment?
init(name: String) {
self.name = name
}
}
class Apartment {
var buildingNumber: String
var roomNumber: String
var `guard`: Person?
var owner: Person?
init(dong: String, ho: String) {
buildingNumber = dong
roomNumber = ho
}
}
각 옵셔널 타입의 매개변수를 지정해주었고 옵셔널 타입이 아닌 변수는 인스턴스 생성과 동시에 초기값을 넣어주려고 한다.
각 클래스를 사용해서 인스턴스를 생성해보았다.
let jay: Person? = Person(name: "jay")
let apart: Apartment? = Apartment(dong: "36", ho: "48")
let superman: Person? = Person(name: "superman")
그럼 여기서 우리집의 경비원에 대해서 알고 싶다면
옵셔널 체이닝을 사용하지 않았을 때 다음과 같이 확인해볼 수 있다.
// 만약 우리집의 경비원이 궁금하다면???
// 옵셔널 체이닝을 사용하지 않을 경우
func guardJob(owner: Person?) {
if let owner = owner {
print("집주인은 \(owner.name) 입니다.")
if let home = owner.home {
print("집은 \(home) 입니다.")
if let `guard` = home.guard {
print("우리집 경비원은 \(`guard`) 입니다.")
if let guardJob = `guard`.job {
print("우리집 경비원의 직업은 \(guardJob) 입니다.")
} else {
print("우리집 경비원은 직업이 없습니다.")
}
} else {
print("경비원이 없습니다.")
}
} else {
print("집이 없습니다.")
}
} else {
print("집주인이 없습니다.")
}
}
========== 출력 결과 ==========
집주인은 jay 입니다.
집이 없습니다.
각각의 값을 조건문으로 비교해서 있는지 없는지 찾아야 한다.
결과를 보면 owner의 home 의 값이 없기 때문에 nil 을 반환하고 함수가 종료된 것을 확인할 수 있다.
이렇게 값의 여부를 확인하려면 각각의 값을 비교해야 한다.
하지만 옵셔널 체이닝을 사용하면 보다 쉽게 비교해 값을 가져올 수 있다.
옵셔널 체이닝을 사용해서 다음과 같이 확인해볼 수 있다.
// 옵셔널 체이닝을 사용했을 때
func guardJobWithOptionalChaining(owner: Person?) {
if let guardJob = owner?.home?.guard?.job {
print("우리집 경비원의 직업은 \(guardJob) 입니다.")
} else {
print("우리집 경비원은 직업이 없어요")
}
}
guardJobWithOptionalChaining(owner: jay)
========== 출력 결과 ==========
우리집 경비원은 직업이 없어요
위와 같이 옵셔널 체이닝을 사용해서 앞에서부터 값을 비교해 나간다.
onwer 의 값이 있다면, onwer 내부의 home 의 값의 여부를 확인한다. 만약 없다면 nil 을 반환한다.
home 의 값이 있다면, home 내부의 guard의 값의 여부를 확인한다. 만약 없다면 nil 을 반환한다.
guard의 값이 있다면, guard 내부의 job의 값의 여부를 확인한다. 만약 없다면 nil 을 반환한다.
위에서 옵셔널 체이닝을 사용하지 않을 때와 같이 home 의 값이 없기 때문에 nil 을 반환하고 else 내부의 결과를 출력하게 된다.
확실히 옵셔널 체이닝을 사용할때와 아닐때의 소스 코드가 간결해진 것을 확인할 수 있다.
매 번 값을 확인하지 않고 한 번에 확인할 수 있다는 점이다.
옵셔널 체이닝을 통해 값을 확인하는 과정을 값을 할당하면서 확인해보았다.
jay?.home?.guard?.job // nil
jay?.home = apart
jay?.home // Optional(Apartment)
home 의 값이 nil 이었기 때문에 home 에 apart 라는 값을 할당해주었다.
그리고 nil 이 아닌 옵셔널 타입의 Apartment 의 값이 할당된 결과를 확인할 수 있었다.
jay?.home?.guard // nil
// 경비원 할당
jay?.home?.guard = superman
jay?.home?.guard // Optional(Person)
그 다음으로 guard 의 값이 nil 이므로 값을 할당해주었다.
superman 이라는 값을 할당해주었고 옵셔널 타입의 Person 의 값이 할당된 결과를 확인할 수 있었다.
jay?.home?.guard?.name // superman
jay?.home?.guard?.job // nil
jay?.home?.guard?.job = "경비원"
jay?.home?.guard?.job // 경비원
그래서 name의 값이 superman 으로 할당되었고 job 은 여전히 nil 값을 반환한다.
그래서 "경비원" 이라는 값을 할당해주었고 할당된 값을 확인했다.
nil 병합 연산자
그럼, nil 값을 반환할 때마다 매 번 값을 할당해줄 수는 없다.
그래서 nil 병합 연산자를 통해서 값을 할당해줄 수 있다.
nil 병합 연산자는 중위 연산자다.
?? , 물음표 두개를 사용해서 표현한다. 예) 옵셔널 ?? 값
옵셔널 값이 nil 일 경우, 우측의 값을 반환한다.
그리고 띄어쓰기에 주의해야 한다.
그럼 nil 병합 연산자를 통해서 값을 할당해보자.
var guardJob: String
guardJob = jay?.home?.guard?.job ?? "슈퍼맨"
// nil 이 아니기 때문에 "경비원"의 값이 출력된다.
print(guardJob) // 경비원
?? 라는 연산자를 통해 nil 일 경우 "슈퍼맨" 이라는 값을 할당하도록 했다.
하지만 위에서 경비원의 직업에는 "경비원" 이라는 값을 할당해주었기 때문에
nil 의 값을 반환하지 않아 "슈퍼맨" 의 값이 할당되지 않고 "경비원" 이라는 값이 출력되었다.
그래서 해당 값을 nil 로 만들어 다시 확인해보았다.
jay?.home?.guard?.job = nil
guardJob = jay?.home?.guard?.job ?? "슈퍼맨"
// 경비원 직업은 nil 로 해주었기 때문에 "슈퍼맨"의 값이 할당된다.
print(guardJob) // 슈퍼맨
경비원의 직업을 nil 로 만든 후 nil 병합 연산자를 통해서 값을 할당해주었다.
job 이 nil 이므로 "슈퍼맨" 의 값이 할당된 것을 확인할 수 있었다.
- 참고 사이트 -
www.edwith.org/boostcamp_ios/lecture/11311/
'iOS > Swift' 카테고리의 다른 글
스위프트는 어떻게 동작할까? (0) | 2020.11.25 |
---|---|
[Swift] 22. 타입 캐스팅 (type casting) (0) | 2020.11.25 |
[Swift] 20. 인스턴스 생성 및 소멸 (init / deinit) (0) | 2020.11.11 |
[Swift] 19. 상속(Inheritance) (0) | 2020.11.09 |
[Swift] 18. 프로퍼티 (Property) - 추가적인 보완 필요 (0) | 2020.11.05 |