옵셔널 체이닝과 빠른 종료

Gooreum·2021년 10월 28일
0

Swift

목록 보기
11/16

옵셔널 체이닝 chaining

  • 정의
    • 옵셔널 체이닝은 옵셔널에 속해 있는 nil일지도 모르는 프로퍼티, 메서드, 서브스크립션 등을 가져오거나 호출할 때 사용할  수 있는 일련의 과정이다.
    • 즉, 옵셔널을 반복 사용하여 옵셔널이 자전거 체인처럼 서로 꼬리를 물고 있는 모양이기 때문에 옵셔널 체이닝이라고 부른다.
    • 중첩된 옵셔널 중 하나라도 값이 존재하지 않는다면 결과적으로 nil을 반환한다.
  • 사용법
    • 옵셔널 체이닝은 프로퍼티나 메서드 또는 서브스크립트를 호출하고 싶은 옵셔널 변수나 상수 뒤에 물음표(?)를 붙여 표현한다.
    • 옵셔널이 nil이 아니라면 정상적으로 호출될 것이고, nil이라면 결괏값으로 nil을 반환할 것이다.
    • 결과적으로 nil이 반환될 가능성이 있으므로 옵셔널 체이닝의 반환된 값은 항상 옵셔널이다.
  • 예제 코드 [1] Person 클래스 설계
    
    class Room { //호실
    	var number: Int //호실번호
    	init(number: Int) {
    		self.number = number
    	}
    }
    
    class Building {  //건물
    	var name: String //건물 이름
    	var room: Room? //호실 정보
    	init(name: String) {
    		self.name = name
    	}
    }
    
    struct Address { //주소
    	var province: String //광역시/도
    	var city: String  //시/군/구
    	var street: String  //도로명
    	var building: Building?  //건물
    	var detailAddress: String? //건물 외 상세 주소
    }
    
    class Person { //사람
    	var name: String  //이름
    	var address: Address?  //주소
    	init(name: String) {
    	self.name = name
    	}
    }

[2] Person 인스턴스 생성

//jacob 인스턴스 생성
let jacob: Person = Person(name: "Jacob")

[3] 옵셔널 체이닝 문법을 사용해보자.

let jacobRoomViaOptionalChaining: Int? = jacob.address?.building?.room?.number // nil발생
let jacobRoomViaOptionalUnwrapping: Int = jacob.address!.building!.room!.number //오류발생
  • jacob에는 아직 주소, 건물, 호실 정보가 없다.
  • 따라서 jacobRoomViaOptionalChaining 상수에 호실 번호를 할당하려고 옵셔널 체이닝을 사용하면 jacob의 address 프로퍼티가 nil이므로 옵셔널 체이닝 도중 nil이 반환된다.
  • 그러나 jacobRoomViaOptionalUnwrapping 상수에 호실 번호를 할당할 때는 '강제 추출'을 시도했기 때문에 nil인 address 프로퍼티에 접근하려 할 때 '런타임 오류'가 발생한다.
  • 옵셔널 바인딩을 사용해보자.
    let jacob: Person = Person(name: "Jacob")
    var roomNumber: Int? = nil
    if let jacobAddress: Address = yagom.address {
    	if let jacobBuilding: Building = jacobBuilding.building {
    		if let jacobRoom: Room = jacobBulding.room {
    				roomNumber = jacobRoom.number
    			}
    		}
    	}
    
    if let number: Int = roomNumber {
    	print(number)
    } else {
    	print("room number를 찾을 수 없습니다.")
    }
  • 옵셔널 체이닝을 사용해서 위의 코드를 좀더 줄여보자.
    let jacob: Person = Person(name: "Jacob")
    if let roomNumber: Int = jacob.address?.building?.room?.number {
    	print(roomNumber)
    } else {
    	print("room number를 찾을 수 없습니다.")
    }
    • 옵셔널 체이닝이 옵셔널 바인딩 기능과 결합할 수 있는 이유는 옵셔널 체이닝의 결괏값은 옵셔널 값이기 때문이다.
  • 서브스크립트에 적용하기
    • 서브스크립트는 인덱스를 통해 값을 넣고 빼올 수 있는 기능을 의미한다.

    • 서브스크립트를 가장 많이 사용하는 곳은 Array와 Dictionary 이다.

    • 옵셔널의 서브스크립트를 사용하고자 할 때는 대괄호([]) 보다 앞에 물음표(?)를 표기해주어야 한다.

      let optionalArray: [Int]? = [1,2,3]
      optionalArray?[1] // 2
      var optionalDictionary: [String: [Int]]? = [String: [Int]]()
      optionalDictionary?["numberArray"] = optionalArray
      optionalDictionary?["numberArray"]?[2] // 3

빠른 종료

  • guard
    • 빠른 종료(Early Exit)의 핵심 키워드는 'guard'이다.

    • guard 구문은 if 구문과 유사하게 Bool 타입의 값으로 동작하는 기능이다.

    • guard 뒤에 따라붙는 코드의 실행 결과가 true일 때 코드가 계속 실행된다.

    • if 구문과는 다르게 guard 구문은 항상 'else' 구문이 뒤에 따라와야 한다.

    • 만약 guard 뒤에 따라오는 Bool 값이 false라면 else의 블록 내부 코드를 실행하게 되는데, 이때 else 구문의 블록 내부에는 꼭 자신보다 상위의 코드 블록을 종료하는 코드가 들어가게 된다.

    • 그래서 특정 조건에 부합하지 않다는 판단이 되면 재빠르게 코드 블록의 실행을 종료할 수 있다.

    • 현재의 코드 블록을 종료할 때는 return, break, continue, throw 등의 제어문 전환 명령을 사용한다.

    • 또는, fatalError()와 같은 비반환 함수나 메서드를 호출할 수 있다.

      guard Bool 타입 값 else {
      	예외사항 실행문
      	제어문 전환 명령어
      }
profile
하루하루 꾸준히

0개의 댓글