반응형
LinkedIn 개발자로 성장하면서 남긴 발자취들을 확인하실 수 있습니다.
Github WWDC Student Challenge 및 Cherish, Tiramisul 등 개발한 앱들의 코드를 확인하실 수 있습니다.
개인 앱 : Cherish 내 마음을 들여다보는 시간, 체리시는 디자이너와 PM과 함께 진행 중인 1인 개발 프로젝트입니다.
10년 후, 20년 후 나는 어떤 스토리 텔러가 되어 있을지 궁금하다. 내가 만약에 아직 조금 더 탐구하고 싶은 게 있고, 궁금한 게 있다면, 그게 설사 지금 당장의 내 인생에 도움이 안 되는 것 같더라도 경험해보자. 그 경험들을 온전히 즐기며 내 것으로 만들고, 내 일에 녹여내고... 그러다보면 그 점들이 모여 나란 사람을 그려내는 선이 될 테니까.

Recent Posts
Recent Comments
Total
관리 메뉴

꿈꾸는리버리

[2/2] optional chaining 본문

오뚝이 개발자/swift

[2/2] optional chaining

rriver2 2022. 5. 14. 21:00
반응형

이전 포스팅에서 optional의 개념과 optional을 unwrapping하는 방법에 대해서 알아봤는데,

느낌적으로 optional binding을 하는 게 최고구나 ! 라는 것을 느꼈을 거다 ㅎㅎ

 

 

 💡 optional chaining  

 

이제 더 나아가서 optional binding과 함께 사용하면 좋은 optional chaining에 대해서 알아보자 !

 

 

하단에는 한 사람의 주소를 나타내기 위한 struct들이다..

person -> address -> building -> room 이렇게 접근이 된다.

struct Person{
    var name : String
    var address : Address?
}

struct Address{
    var city : String
    var building : Building?
}

struct Building{
    var name : String
    var room : Room?
}

struct Room{
    var number : Int
}

 address, building, room은 모두 옵셔널이라는 것을 명심한 채 하단의 내용을 읽어보길 바란다..!

 

 

river.address?.building?.room?.number

이 뜻은 

river.address? -> address가 nil이 아니야? 그럼 building 확인

river.address?.building?  -> building이 nil이 아니야? 그럼 room 확인

river.address?.building?.room?.number  -> room이 nil이 아니야? 그럼 number 확인

요론 느낌 ? 으로 이해를 하면 된다.

 

그래서 number를 확인하기 이전의 단계에서 nil이라는 게 확인이 되면 뒤에꺼는 확인하지 않고 nil을 반환한다.

let river : Person = Person(name: "River")
var river2 : Person = Person(name: "River",address: Address(city: "Busan", building: Building(name: "빌딩이름", room: Room(number: 1004))))

let riverRoomNumber : Int? = river.address?.building?.room?.number
var river2RoomNumber : Int? = river2.address?.building?.room?.number

// 에러 발생 (!은 강제 unwrapping 이라서 nil일 때 런타임 에러가 발생한다. )
//let riverRoomNumber2 : Int? = river.address!.building!.room!.number

// + 요론 식으로 값을 대입할 수도 있다.
river2RoomNumber = 100

 

 

위에서 number 값을 riverRoomNumber에 대입하는 과정을 optional binding으로 적으면 하단의 코드와 같다. 

var river2 : Person = Person(name: "River",address: Address(city: "Busan", building: Building(name: "빌딩이름", room: Room(number: 1004))))

if let address = river2.address{
    if let building = address.building{
        if let room : Int = building.room{
            print(" room 번호 : \(room.number)")
        }
    }
}

한눈에 봐도 알겠지만 위의 optional chaining이 훨씬 가독성이 좋다는 것을 알 수 있다.

 

 

이렇게 optional chaining과 optional binding에 대해서 알아봤는데...

여기 놓치기 쉬운 차이가 있다!

var river2 : Person = Person(name: "River",address: Address(city: "Busan", building: Building(name: "빌딩이름", room: Room(number: 1004))))

// 1) optional chaining 사용
var river2RoomNumber : Int? = river2.address?.building?.room?.number

// 2) optional binding 사용
if let address = river2.address{
    if let building = address.building{
        if let room : Int = building.room{
            print(" room 번호 : \(room.number)")
        }
    }
}

 

optional chaining을 하면 optional 값으로 반환이 된다는 것이다.

앞서 말했던 것처럼 "number를 확인하기 이전의 단계에서 nil이라는 게 확인이 되면 뒤에꺼는 확인하지 않고 nil을 반환한다." 

즉, nil 값이 들어갈 수 있는 것이다.

 

 optional Binding과 optional Chaining 짬뽕 

그래서 optional Binding과 optional Chaining 짬뽕시켜서 사용하는 게 일반적이다.

 

river2.address?.building?.room?.number( optional Chaining )를 통해 optional 값으로 number을 꺼내고, 

if let( optional Binding )을 통해서 unwrapping을 해서 String 값으로 추출하는 것이다 !

var river2 : Person = Person(name: "River",address: Address(city: "Busan", building: Building(name: "빌딩이름", room: Room(number: 1004))))

if let room = river2.address?.building?.room?.number{
    print(" room 번호 : \(room)")
}

 

 


 

+ ) guard let  

if let과 비슷하게 unwrapping을 하는 guard let 을 마지막으로 알아보자 !

 

처음에는 if let과 guard let이 진짜 너무 헷갈렸는데, 쓰다보면 둘의 차이를 명확하게 알게 된다.

 

guard let 의 경우에는 swift 공문에 "Early Exit" title과 함께 나와있다.

말 그대로 nil인 경우에 빨리 해당 블록을 끝내는 거다.

 

 

그래서 하단의 코드를 보면, nil 일때 먼저 return을 하고, 

만약에 nil이 아니라면, 기나긴 코드에서 _room 상수를 사용할 수 있고 마지막에 함수를 종료하게 된다.

var river2 : Person = Person(name: "River",address: Address(city: "Busan", building: Building(name: "빌딩이름", room: Room(number: 1004))))

func printRoomNumber(river : Person){
    guard let _room = river.address?.building?.room?.number else{
        print("nil 값")
        return
    }
    // 기나긴 코드들
    print(_room)
}

printRoomNumber(river : river2)

 

둘의 차이를 알아보자면, 다음과 같다.

if let guard let
A는 지역변수로만 사용 가능 → 블록 안에서만 A 사용 가능 else 이후 블록 밖에서 쭉 A 사용 가능
조건문의 Optional 값이 nil인지 확인가능 조건문의 Optional 값이 nil인지 확인가능


guard let 구문은 먼저 else 를 통해 빨리 exit 시킴

1. 값이 있을 때 else 이후의 코드가 실행
2. 값이 없을 때 else 문이 실행되며, 상위 코드 블럭을 종료하는 함수인 continue, break return, throw 등이 반드시 필요

 

// 1) if let

if let A = B {
    // B가 nil이 아닐때
    // A 사용 가능
}else {
    // B가 nil일 때
    // A 사용 x
}
// A 사용 x
//2) guard let

guard let A = B else{
	// B가 nil일 때
	return 
}
// B가 nil이 아닐때 
// A 사용 가능

 

+ if let과 마찬가지로 quard let으로 unwrapping 할 때도 조건을 다는 것이 가능하다 ! 

 


optional을 처음 만났을 때 봤던,, "optional은 enum이다!" 와 관련해서 좋은 자료가 있어 덧붙이면,

 forced unwrapping  and optional binding  

 implicitly unwrapping optional  

the Nil-Coalescing Operator  

 

optional chaining

출처 : https://www.youtube.com/watch?v=gI3pz7eFgfo&list=PL3d_SFOiG7_8ofjyKzX6Nl1wZehbdiZC_

 

반응형
Comments