티스토리 뷰

반응형

 

Swift Docs의 Implicitly Unwrapped Optionals 와  Unowned References and Implicitly Unwrapped Optional Properties 에 나오는 내용을 기반으로 하고 있습니다.


 

[1] Implicitly Unwrapped Optional 이란? 

 

'암묵적으로(암시적으로) 언래핑한 옵셔널' 이라는 용어그대로

옵셔널이지만 언래핑하지 않고 사용할 수 있는 옵셔널을 말합니다.

 

Optional을 만들 때 question mark(물음표)를 사용했다면 (ex. String?)

Implicitly Unwrapped Optional을 만들 때는 exclamation point(느낌표) 를 사용해주면 됩니다. (ex. String!)

 

 

아래의 예제는 optional string 과 implicitly unwrapped optional string 의 차이를 보여줍니다.

implicitly unwrapped optional string 은 non-optional value처럼 사용될 수 있는 것을 볼 수 있습니다. 

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation point

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation point

implicitly unwrapped optional 은 optional에 force unwrap 권한을 준 것이라고 생각할 수 있으나,

사실 Swift는 가장 먼저 implicitly unwrapped optional을  ordinary optional value 로 다루고

optional로 사용할 수 없는 경우에만 force unwrap 합니다.

 

위의 예제를 다시 볼까요?

String 타입(explicit, non-optional type) 인 implicitString에 값을 assign하려면

implicitly unwrapped optional을  force unwrap 해야하니까 한 것이고

let implicitString: String = assumedString // no need for an exclamation point

 

아래 예제처럼 타입을 명시안했을 경우에는

optionalString은 String? 타입인 것을 볼 수 있습니다.

즉 기본적으로 implicitly unwrapped optional를 옵셔널로 다루고

옵셔널로 다룰 수 없는 경우에만  force unwrap하는 것이죠! 

let optionalString = assumedString
// The type of optionalString is "String?" and assumedString isn't force-unwrapped.

 

이것 외에는 Implicitly Unwrapped Optional 는 Optional이랑 동일합니다. 

 

기본 값이 nil이고

var assumedString: String!
print(assumedString) // nil

 

nil인데 wrapped value에 접근하려고 하면 런타임에러가 나고

var assumedString: String!
print(assumedString!) // Runtime Error!

 

nil체크도 할 수 있고

if assumedString != nil {
    print(assumedString!)
}

 

optional binding으로 check & unwrap도 할 수 있습니다.

if let definiteString = assumedString {
    print(definiteString)
}

 

 

[2] Implicitly Unwrapped Optional 왜 필요하나?

그럼 Implicitly Unwrapped Optional 은 왜 필요할까요?

때때로 value가 처음 set 된 이후부터 optional이 항상 value를 가진다는 것이 확실한 경우가 있습니다.

항상 value가 존재하는 것이 보장되는데,  optional의 value을 체크하고 언래핑하는 코드를 매번 작성하는 것은 불필요합니다.

 

이런 경우, Implicitly unwrapped optional을 사용해주면 유용합니다! 

 

 

[3] Implicitly Unwrapped Optional 실전 예제

implicitly unwrapped optional을 주로 사용하는 경우는 바로 class initialization 할 때입니다. 

 

Unowned References and Implicitly Unwrapped Optional Properties 에 나오는 예제를 살펴볼게요! 

 

Country와 City가 있습니다.

모든 country는 반드시 capital city를 가져야하고 모든 city는 반드시 country에 소속되어있어야합니다. 

이것을 표현하기 위해서 Country는 capitalCity 라는 프로퍼티를, City는 country라는 프로퍼티를 가지도록 해줍니다.

 

개념 상, 두 프로퍼티는 optional이 아니여야합니다. 

하지만 이를 코드로 표현하면 컴파일 에러가 납니다.

Country 인스턴스가 fully initialized 되기 전까지는 self를 넘길 수 없기 때문입니다. (참고: Two-Phase Initialization)

 

 

그래서 capitalCity를 옵셔널로 선언해주자니,

capitaclCity는 반드시 존재하는데 계속 언래핑을 해서 사용해야되고,,, 불편하겠죠?

 

 

이 때 capitalCity 프로퍼티를 implicitly unwrapped optional 프로퍼티로 선언해줄 수 있습니다!

 

 

그럼 capitalCity 프로퍼티는 디폴트 값으로 nil을 가지게 되므로 

Country는 name 프로퍼티가 세팅되자마자 fully initialized 됩니다. (모든 stored property들의 값 세팅이 완료되었으므로)

그래서 Country initializer는 self를 넘길 수 있게 됩니다. 

 

implicitly unwrapped optional 을 사용해줌으로써 Class Initialization 요구사항도 만족시키고 capitalCity property를 non-optional value 처럼 언래핑안하고 사용할 수도 있게 되었네요.

var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// Prints "Canada's capital city is called Ottawa"

 

 

우리가 자주 사용하는 IBOutlet 도 동일한 이유로

Implicitly Unwrapped Optional 입니다! 

class ViewController: UIViewController {
   @IBOutlet var label: UILabel!
    ...
}

 

 

반응형
댓글