옵셔널 체이닝과 빠른 종료

- 옵셔널 바인딩을 하는 것인데 여러 값이 중첩된 형태를 띄우는 형태를 말한다

- 옵셔널을 이해하지 못하고 Swift를 사용한다면 절반도 이해하지 못한다고 할 정도로 중요한 개념이 옵셔널이다

 

옵셔널 체이닝

- 옵셔널에 속해 있는 nil일지도 모르는 프로퍼티, 메서드, 서브스크립트 등을 가져오거나 호출할 때 사용할 수 있는 일련의 과정

  - 옵셔널이 nil이면 모두 nil을 반환한다.

  - 당연히 nil이 아니면 제 값을 반환/호출한다

- 옵셔널을 반복 사용하여 옵셔널이 체인처럼 꼬리를 물고 있는 모양을 말한다

 

느낌표(!)의 사용

  • 값을 강제로 추출하기 때문에 옵셔널에 값이 없다면 런타임 오류가 발생한다
  • 또한 반환값은 옵셔널이 아니라는 점이다
  • 따라서 옵셔널이 아닌 타입에 nil 이 들어오는? 오류가 발생한다
  • 무조건 100% nil이 아니라고 확신하더라도 사용을 지양하는 것이 좋다

 

let optionalChaining: Int? = person.address?.building?.room?.number // nil

let oprionalUnwrapping: Int = person.address?.building?.room?.number // 런타임 오류

 

빠른 종료

- 옵셔널을 추출할 때 사용되는 guard가 핵심이다

- if 문과 유사하게 Bool 타입으로 동작한다

- B.U.T. guard 뒤의 구문이 false 라면 else 블록 내부 코드를 실행하게 되는데, 여기서 블록 내부에는 자신보다 상위의 코드 블록을 종료하는 코드가 들어가야합니다

- guard 구문을 사용해서 함수나 블록에서 쓸데없이 모두 진행할 필요없이, 앞에서 옵셔널을 추출한 후에 nil이라면 바로 블록을 나올 수 있다 -> 이게 바로 빠른 종료를 이용하는 것이다

 

guard Bool타입 else{
	예외상황 실행문
    상위 코드 블록을 종료하는 코드
}

 

func enterClub(name: String?, age: Int?){
	guard let name: String = name, let age: Int = age, age > 19, name.isEmpty == false else{
    	print("넌 너무 어려서 못 들어간다!")
        return // 반환 타입이 Void기 때문에 어떠한 값도 반환하지 않는다
    }
    
    print("어서오세요 \(name)")
}

//대충 예가 기억이 안나서 이 사람이 클럽에 들어갈 수 있는가?라는 함수를 작성해보자

func canEnterClub(name: String?, age: Int?) -> Bool{
	guard let name: String = name, let age: Int = age, age > 19, name.isEmpty == false else{
    	print("넌 너무 어려서 못 들어간다!")
        return false // 반환 타입이 Bool이기 때문에 Bool 타입의 값을 반환하는데, 이 사람은 들어갈 수 없으므로 false를 반환
    }
    
    print("어서오세요 \(name)")
}

 

하... 이제 옵셔널이다

 

옵셔널

- 사실 옵셔널에는 내용이 굉장히 적다.

- B.U.T. 어느 문법이던 중요하겠지만 Swift에서도 굉장히 중요한 표현이다

- 안드로이드 개발을 진행할 때는, 옵셔널이라는 명칭보다는 nullable이라는 단어를 사용했다.

- 스위프트의 특징인 안전성을 담보로 사용할 수 있는 기능이다

- 옵셔널과 옵셔널이 아닌 값은 철저히 다른 타입으로 인식하기 때문에, 컴파일 시점에서 오류를 걸러낸다.

 

그렇다면 왜 옵셔널을 사용하는가?

  • 함수의 전달인자의 값이 잘못된 값일 때
  • 매개변수를 굳이 넘기지 않아도 될 때
  • 열거형을 불러올 때, case에 존재하지 않을 때

앞에서 enum에서 알아봤 듯이, 옵셔널은 열거형이다

 

옵셔널 추출

  • 옵셔널 바인딩
    • if 사용 - if블록 내에서만 사용 가능
    • guard 사용 - 블록외의 블록에서 사용 가능
  • 암시적 추출
    • ! 사용 - 위험한 방법
struct Person{
	var name: String?
}

var person: Person = Person(name: "tree")

//if 사용
if let name = person.name{
	print(name) // tree
}

//guard 사용
guard let name = person.name else { ... }

print(name) // tree

//암시적 추출 사용(1)
let name = person.name!
print(name) // tree

var person2 = Person()
let name2 = person2.name! // 런타임 에러 발생

 

+ Recent posts