안녕하세요!
오늘은 옵셔널 시리즈의 마지막글로 옵셔널 체이닝에 대해 알아보겠습니다!!
❓ Optional Chaining
Chaining이라는 단어를 들으면 어떤 느낌을 받으실까요?
체인이 막 연결되어 있는 형태니까 얘도 이런 걸 뜻하는 게 아닐까~?라고 하신다면 맞습니다!
옵셔널을 연쇄적으로 사용하는 것이거든요!
저만 그런지는 모르겠지만.. 개발 중에 객체 내 해당 프로퍼티가 옵셔널타입이었던걸 잊어버릴 때가 있습니다
그래서 무작정 불러와! 하고 쓰게 되죠😅 바로 아래처럼요
// yunie라는 인스턴스의 pet이라는 프로퍼티에 접근해서 petName을 가져와줘
yunie.pet.petName
그런데 만약 저 yunie인스턴스와 그의 내부 프로퍼티인 pet이 옵셔널 타입이라면..?
옵셔널을 해제해주는 어떠한 과정도 거치지 않은 상태서 무작정 값을 꺼내오라고 하니 오류가 발생할겁니다
하지만 우리의 친절한 Xcode는 저렇게 타이핑하더라도 자기가 알아서 얘네들 옵셔널 타입인데 하고 명시해 주게 돼요
yunie?.pet?.petName
그리고 이처럼 .(dot)을 이용해 옵셔널 프로퍼티나 메서드에 연속적으로 접근할 때, ?와 함께 이어지는 것을 옵셔널 체이닝이라고 합니다
이제 차근차근히 단계별로 살펴볼게요!
struct User {
var name: String
var age: Int
var pet: Pet?
}
struct Pet {
var name: String
var age: Int
}
우선 이런 구조체가 두 가지 있다고 해볼게요
그리고 yunie라는 인스턴스를 User? (옵셔널 타입)으로 생성해 줍니다
let yunie: User? = User(name: "yunie", age: 1)
그리고 yunie라는 사용자의 나이를 알기 위해 무지성으로 접근하게 된다면?
너 왜 옵셔널 타입인 yunie(User?)를 언래핑도 안 하고 내부 프로퍼티에 접근하려고 해? 하면서 컴파일러가 에러를 띄우게 됩니다..!
그래서 yunie 내의 age라는 프로퍼티에 접근해 주는 dot 이전에 ?를 집어넣어 보기로 했습니다
그럼 이렇게 아무 에러 없이 값을 제대로 불러오는 것을 알 수 있습니다
이처럼 옵셔널 타입 데이터의 멤버에 접근할 때에는 해당 데이터가 nil일 수도 있기 때문에 ?를 통해 접근해줘야 합니다
(아니면 옵셔널 바인딩을 해줘야겠죠!)
옵셔널 체이닝이 언제 사용되는지 알았다면 옵셔널 체이닝이 어떤 방식으로 동작하는지 알아봅시다
🧐 옵셔널 체이닝은 어떻게 동작할까?
옵셔널 체이닝은 아주아주 간단합니다!
지금 접근하려는 데이터가 nil인가? 하고 의문을 가진 이후, 그 결과에 따라 더 타고 들어가거나 그 자리에서 nil을 반환하거든요!
방금의 코드를 예로 보자면~ 컴파일러는 yunie 내부의 age값을 가져오기 이전에 yunie라는 인스턴스가 혹시 nil인가? 하고 yunie라는 인스턴스를 먼저 살펴보게 됩니다
그리고 위에 yunie를 제대로 생성해 줬기 때문에 yunie라는 인스턴스는 값이 있구나! 하고?를 지나 age로 넘어가게 됩니다
그럼 만약에 yunie라는 인스턴스가 nil로 초기화되어 있다면?
엥! yunie가 nil이잖아? 하면서? 뒤로 더 넘어가지 않고 그 자리에서 바로 nil을 출력해 주게 됩니다
이처럼 옵셔널 체이닝은 옵셔널 타입인 데이터들에 접근할 때 어떠한 데이터가 nil이라면 그 자리에서 스탑! 아니면 계속해서 타고 가는 방식으로 동작합니다
옵셔널 체이닝이 어떤 건지 이해가 됐다면 이제는 옵셔널 체이닝의 또 다른 특징들에 대해 알아볼 차례입니다!
🧐 옵셔널 체이닝의 결괏값은 항상 옵셔널 타입
아까처럼 제대로 된 yunie라는 인스턴스가 존재하는 상황에서 age에 대해 접근해 해당 데이터의 타입을 불러와보면..
우리의 age 타입은 Optional Int가 됩니다
분명 User라는 구조체 내에서 age는 평범한 Int인데도 불구하고요
그 이유는 아주 간단합니다!
옵셔널 체이닝의 가장 주요한 특징은 nil이 있는 데이터를 만나면 그 자리에서 즉시 nil을 반환한다였습니다
즉, 그 뒤에 데이터가 어떤 타입이건 간에 중간에 nil을 반환할 수도 있기 때문에 nil이 들어갈 수 있는 옵셔널 타입으로 반환되는 것입니다
🧐 함수의 반환값이 옵셔널이라면?
만약 지금처럼 어떠한 데이터가 옵셔널인 게 아니라 함수 자체가 옵셔널을 반환한다고 생각해 봅시다
struct User {
var name: String
var age: Int
var pet: Pet?
func getPet() -> Pet? {
return pet
}
}
그럼 어떻게 사용해줘야 할까요?
위의 예시들과 다를 것 없이 이 함수를 호출되면 옵셔널 타입이 반환된다~를 알리기 위해 함수 호출문 바로 뒤에 ?를 붙여주면 됩니다!
yunie?.getPet()?.name
그리고 이 경우와 유사하게 함수 자체가 옵셔널인 경우라면 함수의 호출문 앞에서 ?를 이용해 함수에 대한 옵셔널을 처리할 수 있습니다
이런 식으로요!
some.getSome?()
🧐 함수 자체가 옵셔널이면서 반환값도 옵셔널이라면?
방금처럼 함수를 호출하지 않고 저 함수를 어떠한 상수에 대입해 봅시다
let someFunc = yunie?.getPet
그럼 someFunc라는 상수는 이렇게 함수 자체를 담고 있는 상태가 됩니다
그리고 이 someFunc을 이용해 Pet의 name을 출력하려고 하면 이러한 형태로 사용해야 합니다
function?()?.age
생긴 게 조금 어렵죠?
그래도 하나씩 뜯어보면 전혀 어렵지 않습니다!
우선 function이 담고 있는 함수인 getPet 함수가 옵셔널 타입인지 확인합니다
여기서는 첫 번째 괄호인 (...)? 부분을 뜻해요
만약 함수가 nil이 아니라면 첫번째 괄호 안의 () -> Pet? 부분을 확인하게 됩니다
이때, 반환되는 데이터에 값이 있는지 없는지 확인하는 과정을 거치게 되고 값이 있다면(pet이 존재한다면) pet의 age를 가져옵니다
생각했던 것보다 복잡하지는 않죠?
🧐 딕셔너리의 값에 접근할 때도 옵셔널 타입!
자, 아래와 같은 딕셔너리가 있다고 해볼게요
let dic = ["Soccer": "Son", "Baseball": "SAMSUNG"]
저는 여기서 Baseball이라는 key의 value를 lowercased()로 가져오고 싶어 졌습니다
그래서 dic["Baseball"].lowercase() 하고 코드를 적어줍니다
그런데 여기서 Xcode가 또다시 친절하게 값을 불러오는 경우에 ?를 넣어줍니다
dic["Baseball"]?.lowercased()
왜냐하면 저 dic이라는 딕셔너리에 Baseball이라는 key 자체가 없을 수도 있거든요
그러면 당연히 nil이라는 값이 나올 거라 자연스럽게 딕셔너리 내 값에 접근할 때에는 옵셔널 타입으로 반환됩니다
엥? 그냥 value를 담아줄 때는 안 그랬는데요? 라는 생각이 드시면 아마 이런 경우일 것 같아요
let val = sports["Baseball"]
하지만 이를 Xcode에서 확인해 보면
이렇게 옵셔널 타입이 담긴 것을 확인할 수 있습니다
옵셔널 체이닝은 마지막 결괏값에 대해서는 옵셔널이라도 ?를 찍지 않는 게 규칙이기 때문에 이런 형태로 보이게 됩니다!
✏️ 오늘의 요약
마무리
와! 길고 길었던 옵셔널에 관한 글 정리가 끝났습니다!
사실 이보다도 더 많은 사용법이 있겠지만 일단은 이 정도로만 정리해 두고! 추후에 또 알게 된 내용이 있거나 보강이 필요하다고 생각되면 수정해 볼게요! 🤗
'Swift' 카테고리의 다른 글
❓ Enum(1) (0) | 2024.07.10 |
---|---|
❓ Switch-Case (0) | 2024.07.08 |
❓Nil Coalescing (??) (0) | 2024.07.03 |
❓ Implicitly Unwrapped Optional (1) | 2024.07.01 |
❓ Optional Binding (0) | 2024.06.28 |