[Swift] 옵셔널 언래핑 방법들 정리

11753 단어 swiftswift

옵셔널 언래핑 방법들 정리

https://babbab2.tistory.com/16?category=828998의 시리즈

Optional unwrapping : 옵셔널로 감싸진 옵셔널이 아닌 값을 추출하는 작업

주의 - 옵셔널 언래핑의 대상이 nil이어서는 안 된다.

(nil은 값이 아니다!! 값이 없음을 나타내는 개념임)

1. 강제 추출 Forced Unwrapping

옵셔널의 실제 값에 상관없이 강제로 값을 추출하는 것

옵셔널이 nil일 때 강제추출을 사용하면 에러가 발생

사용하지 않는 것이 좋다

2. 옵셔널 바인딩 Optional Binding

안전하게 옵셔널 값을 언래핑 하는 방법으로, 가장 많이 사용한다.

if let ..., guard let ... else 가 주로 사용된다.

공통적으로

  1. 옵셔널 표현식 작성 (if let 임시상수 = 옵셔널값 또는 guard let 임시상수 = 옵셔널값)
    • 타입 추론이 되므로 타입 어노테이션은 대부분 생략
  2. 옵셔널값이 nil이 아니라면 : 임시상수에 옵셔널 언래핑된 값이 저장되고, true 반환
  3. 옵셔널값이 nil이라면 : false 반환

if let

let 옵셔널숫자: Int? = 4
if let 임시상수 = 옵셔널숫자 {
   // '옵셔널숫자'가 nil이 아닐 때 
   print(임시상수)
} else {
   // '옵셔널숫자'가 nil일 때
   print(옵셔널숫자)
}

사용 시 유의점

  • 임시상수의 스코프는 if 구문이다.
  • 옵셔널숫자의 값은 여전히 옵셔널이다.

if let - 여러 개의 옵셔널값 바인딩 및 조건 추가

let name: String? = nil
let age: Int? = nil

if let name = name, let age = age, age > 5 {
    // name과 age 가 모두 nil이 아니고, age가 5보다 커야 if 구문이 true가 됨.
}

guard let

guard let 임시상수 = 옵셔널숫자 else {
   // "옵셔널숫자" 가 nil임
   return
}
// "옵셔널숫자" 가 nil이 아님
// 이 스코프에서 "임시상수" 사용 가능

guard = 지키다 라는 뜻.

  • 특성상 함수(메서드)에서만 사용됨
  • guard문의 조건을 만족하지 못하면 else문으로 처리되며, 함수는 리턴됨
    • 반드시 else와 함께 사용 - 조건 불만족시 리턴시켜야 하기 때문

guard 조건을 만족하지 못하면 함수 내로 들어오지 못하도록 "막는" 역할!

유의할 점

  • else 문에서는 임시상수를 사용할 수 없음

guard let - 여러 개의 옵셔널값 바인딩 및 조건 추가

func test(_ name: String?, _ age: Int?) {
   guard let name = name, let age = age, age < 5 else {
      return
   }
}

if let 과 guard let 비교

  • if let
    • 옵셔널 값 있으면 if구문에서 처리하고, nil이면 else에서 처리해.
    • 옵셔널 값의 경우에 대한 피드백을 제공할 때 사용
  • guard let
    • 옵셔널 값 있으면 계속 진행하고, 없으면 내 함수에서 나가.
    • 옵셔널 값이 nil인 경우 무조건 함수를 종료시키고 싶을 때 사용

3. 옵셔널 묵시적 추출 IUO - Implicitly Unwrapped Optional

강제 추출이나 옵셔널 바인딩처럼, 별도의 추출 과정을 거치지 않아도 자동으로 옵셔널이 해제되는 방법.

주의 - 옵셔널 타입을 옵셔널이 아닌 타입에 대입할 때, 별도의 언래핑 없이 자동으로 추출해 준다. 아무 때나 자동으로 추출해 주는 것이 아님.

var num: Int? = 4
var num2: Int = num 
// 에러 발생 - 옵셔널 타입을 옵셔널이 아닌 타입에 대입하려 하기 때문

var num: Int! = 4 // IUO 사용
var num2: Int = num // num2의 값은 4이다
// 정상 작동 - IUO를 사용했기 때문
  • 방법 : 타입 어노테이션 뒤에 !를 붙인다.
  • let name: String!
  • IUO 역시 옵셔널 타입이다.
  • IUO 역시 내부적으로 강제추출을 한다.
    • 옵셔널 값이 nil인 경우에는 묵시적 추출을 하려 해도 에러가 발생한다.

왜 쓰는가?

IUO는 "프로퍼티 지연 초기화"를 하기 위해 사용한다.

실제로 개발자가 직접 IUO를 쓰기보다는

  • IBOutlet
  • API 에서 IUO를 리턴한 경우

외에는 옵셔널 바인딩을 사용하자.

4. ?? 연산자 - nil 병합 연산자 (Nil-Coalescing Operation)

옵셔널값 ?? 기본값

옵셔널 값이 nil이 아니면 옵셔널을 언래핑한 값을, nil이면 ?? 뒤의 기본값을 사용

  • 옵셔널값기본값은 옵셔널을 벗기면 동일한 타입이어야 한다.

5. 옵셔널 체이닝 Optional Chaining

체이닝 = 연쇄.

따라서 옵셔널 체이닝 = 옵셔널을 연쇄적으로 사용하는 것.

  • .(dot)을 통해 내부 프로퍼티나 메서드에 연속적으로 접근할 때, 옵셔널 값이 하나라도 포함되어 있다면 그것을 옵셔널 체이닝이라고 한다.
    • 예시1 : person.contacts?.address
    • 예시2 : person?.getContacts()?.email
  • 옵셔널 표현식의 멤버에 접근할 때, 표현식이 nil일 수 있기 때문에 ?를 붙여주는 것이다.
    • 만약 표현식이 nil이면, 전체 값도 nil 이 된다.
    • 만약 표현식이 nil이 아니라면, 언래핑된 값으로 연쇄 접근한다.
  • 옵셔널 표현식의 결과값은 항상 옵셔널이다.

유의사항

  • 옵셔널 체이닝 결과 타입은 마지막 표현식의 옵셔널 타입이다.
  • 옵셔널 체이닝의 마지막 표현식은 옵셔널이더라도 ?를 생략한다.
  • 옵셔널 표현식의 멤버(프로퍼티/메서드) 중 메서드에 접근할 때,
    • 리턴값이 옵셔널이면 괄호 뒤에 메서드명()?으로 작성
    • 예시 : person?.getContacts()?.email
    • 메서드 자체가 옵셔널인 경우 메서드명?() 으로 작성
      • 예시 : function?().email
    • 메서드 자체도 옵셔널이고, 리턴값도 옵셔널이면 메서드명?()? 으로 작성
      • 예시 : function?()?.email
  • 옵셔널 표현식의 멤버 중 딕셔너리에 접근할 때
    • 딕셔너리 키 값으로 얻은 값의 속성에 접근할 때 []? 로 작성
      • 예시 : dic["name"]?.count
struct Contacts {
  var email: String
  var address: String
}

struct Person {
  var name: String
  var contacts : Contacts
  
  init(name: String, email: String, address: String) {
    self.name = name
    contacts = Contacts(email: email, address: address)
  }
}

var tom: Person? = Person(name: "Tom", email: "[email protected]", address: "Seoul")

tom.contacts.email // 에러 - tom 이 옵셔널 타입이기 때문.
tom?.contacts.email // OK - 만약 tom이 nil이면 전체 값도 nil 로 처리됨.

좋은 웹페이지 즐겨찾기