본문 바로가기

공부/iOS

Swift - Optional 2 ( Optional Binding, Implicitly Unwrapped Optionals)

시작하기 전에 요약을 잠깐 해보자면 Optional Binding과 Implicitly Unwrapped Optional 은 둘다 옵셔널을 해제하는 방법이에요.

둘다 사용자가 명시하는 명시적 해제이며

Optional Binding은 비 강제적인 해제이며 

Implicitly Unwrapped Optionals 는  암묵적 해제입니다.

 

 

그럼  저번 시간에 이어서 옵셔널 문서를 계속 볼게요

검정글씨는 공식문서를 번역한거고 보라색은 책과 제 생각을 정리한 글입니다.

 

Optional Binding

당신은 옵셔널 바인딩을 사용하여 옵셔널 변수(상수)가 값을 포함하고 있는지의 여부를 알아 낼 수 있습니다.
그리고 만약 값이 있을때 일시적인 상수나 변수로 만들수 있습니다.

옵셔널 바인딩은 if문과 while문과 함께 사용할 수 있습니다. 
옵셔널 내에서 값을 확인하고,해당 값을  상수 또는 변수로 추출합니다.

 

다음 예제와 같이 if 문에 대한 옵셔널바인딩을 작성할 수 있습니다.

// 옵셔널 바인딩 사용법
if let constantName = someOptional {
	//constanName 사용가능
}

 

저번 시간에 학습했던 possibleNumber은 강제 해제대신 아래와 같이 옵셔널 바인딩을 사용하여 다시 쓸 수 있습니다.

if let actualNumber = Int(possibleNumber) {
    print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
    print("The string \"\(possibleNumber)\" could not be converted to an integer")
}
// Prints "The string "123" has an integer value of 123"

(if let과 마찬가지로 guard let도 사용할 수 있어요.)

 

위의 코드는 다음과 같이 해석할 수 있습니다.

 

Int(possibleNumber)에서 반환되는 옵셔널 Int에 값이 포함되어 있는 경우 actualNumber이라는 새로운 상수에 대입합니다.

 

변환에 성공하면 if문의 첫번쨰 분기내에서 actualnumber상수를 사용할 수 있습니다.

이 상수는 이미 초기화 되었기 때문에 ! 접미사를 사용하여 해당 값에 액세스할 필요가 없습니다.

이 예제에서는 realNumber를 사용하여 변환 결과를 인쇄합니다.

옵셔널 바인딩으로 상수와 변수를 모두 사용할 수 있습니다.

 

if문의 첫번째의 actualNumber의 값을 조작하려면 "if var actualNumber"로 선언하여 사용하면 됩니다.

 

그렇게 하면 if문 안에 있는 actuanlNumber는 상수가 아닌 변수로 사용할 수 있습니다.

필요한 경우 옵셔널 바인딩과 if의 BOOL 조건을 같이 쓰고 싶다면 같이쓰는 대신에 ,로 구분하면 됩니다.

 

옵셔널 바인딩의 값 중 하나가 nil이거나 BOOL 조건이 false 로 평가되면 if문 조건 전체가 false 로 간주됩니다.

 

if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"

if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}
// Prints "4 < 42 < 100"

 

Implicitly Unwrapped Optionals(암묵적 옵셔널 해제)

위에서 설명한데로 옵셔널은 상수나 변수가 값이 없음을 허용해준다는것을 표시해줍니다.

 

if 문으로 옵셔널 값을 확인할 수 있으며, 옵서녈 값이 있는 경우 옵셔널 값에 액세스 하기 위해 옵셔널 바인딩으로 조건부로 옵셔널 값을 해제할수 있습니다.

 

가끔은 프로그램 구조상 옵셔널 값에는 해당 값이 처음 설정된 후 항상 값이 있다는 것이 명확할 수도 있습니다.

(설계상, 코드상으로 절대로 nil이 되지 않을거라고 확신하는 변수나 상수에 사용한다는데... 저는 자주 안쓰게 되더라구요 불안해서 ..ㅋ)

 

이러한 경우에는 옵셔널의 값이 항상 값을 갖는다고 안전하게 가정할 수 있기 때문에 옵셔널의 값을 액세스 할때마다 확인하고 해제할 필요가 없어집니다.

 

이러한 유형의 옵셔널은 암묵적 옵셔널 해제라고 정의됩니다.

 

보통의 옵셔널은 자료형뒤에 ?를 붙여서 표현하지만 암묵적 옵셔널 해제는 자료형 뒤에 !를 배치하여 선언합니다.

 

사용할때는 선언된 변수나 상수 뒤에 느낌표를 배치하지 않고 선언할 때 옵셔널 타입 뒤에 !를 붙여서 선언합니다.

(쉽게 var a: String? 은 기본 옵셔널 var b: String!은 암묵적 옵셔널 이라고 생각하면 편해요.)

 

암묵적 옵셔널 해제는 옵셔널 값이 처음 선언될때 값이 존재하고 그 후에도 계속 값이 존재할때 유용하게 사용됩니다.

 

스웨프트에서는 암묵적 옵셔널 해제의 주요 용도는 클래스 초기화 중에 사용됩니다.

(Unowned referece, Implicitly Unwrapped Optional Properties) 

 

암시적 옵셔널 해제로 선언한 변수는 다음부터는 일반 변수,상수 처럼 사용 할 수 있습니다.(!나 옵셔널바인딩으로 풀지 않아도 됩니다.)

 

다음 예제는 String에 대한 암묵적 옵셔널 해제와 명시적 옵셔널 해제의 사용법의 차이점을 보여줍니다.

 

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

 

당신은 필요할 경우 "옵셔널"을 "강제 옵셔널 해제"할 수 있는 관한을 부여한 것으로 "암묵적 옵셔널 해제"를 생각할 수 있습니다.
(뭔 소리지..? 쉽게 암묵적 옵셔널 해제로 선언한 변수는 옵셔널로 선언한 변수뒤에 !를 자동적으로 붙여준다고 생각하면 될거같아요.)


당신이 "암묵적 옵셔널 해제"를 사용하면, 스위프트는 처음으로 일반 옵셔널 값을 사용하려고 시도합니다

 

만약 그것을 옵셔널로 사용할 수 없다면, 스위프트는 강제로 값을 해제(unwraps) 합니다.

 

위의 예제를 보면 
옵셔널 값인 assumedString이 implicitString에 할당 했는데 implicitString의 타입이 옵셔널이 아니므로 강제 해제되어 할당되었습니다.

 

아래 코드에서 optionalString은 명시적 타입이 없으므로 옵셔널 타입입니다.

 

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

(위의 예제에서 optionalString을 print하면 Optional("XXXX")라는 값을 출력합니다. 암묵적 옵셔널 해제도 결국은 옵셔널이라는거죠~)

 

만약 암묵적 옵셔널 해제 타입의 값이 nil이고 당신이 그 값을 사용하려고 한다면 런타임 오류가 납니다.

결과는 뒤에 느낌표를 배치한 것과 동일합니다.

암묵적 옵셔널 해제도 기본 옵셔널과 같이  nil체크를 할 수 있습니다.

 

if assumedString != nil {
    print(assumedString!)
}
// Prints "An implicitly unwrapped optional string."

 

또한 암묵적 옵셔널 해제 역시 옵셔널 바인딩을 이용하여 포장해제를 하여 새로운 변수나 상수에 대입하여 사용할 수 있습니다.

 

if let definiteString = assumedString {
    print(definiteString)
}

 

 

후.. 이렇게 스위프트 공식문서에 Basic에 있는 옵셔널 기본에 대한 내용의 정리가 끝났는데요...

원래 알던 내용이지만 공식문서를 보니까 잘 이해가 안되는 부분이 있었네요.. ㅋㅋ

 

간단하게 쉽게 정리하자면

Swift언어의 기본은 Non-Optional이여서 var a: String = nil 이라고 하면 컴파일 오류가 발생해요.

그런데 변수에 nil이 들어가는 경우는 매우 많으니 Optional이라는 녀석을 제공해주죠.

Optional Int와 Int는 같은타입이 아니고, Optional Int를 print해보면 Optional(123) 이런식으로 나오죠.

그럼 Optional Int와 Int가 같은 타입이 아니니까 사용하거나 값을 비교할대 Optional 값을 포장해제(Unwrapping)해야 되는데~

여기서 방법이 몇가지 있어요~

 

옵셔널 해제방식은 크게 2가지로 나뉘는데 명시적해제와 암묵적 해제가 있어요.명시적해제와 암묵적 해제는 또 2가지로 나뉘는데 

  • 명시적 해제
    • 강제적인 해제 (전 포스트에서 다룬내용이죠~ 옵셔널 상수나 변수 뒤에 !를 붙인거요.)
    • 비강제적인 해제 (이번 포스트에서 다룬 옵셔널 바인딩이에요)
  • 암묵적 해제
    • 옵셔널 암묵적 해제(이번 포스트에서 다룬 내용이죠. 선언할대 타입 뒤에 !를 붙인거요~)
    • 컴파일러에 의한 자동 해제 (정리하지 않았지만 비교연산자를 사용할 때 컴파일러가 자동으로 옵셔널을 해제하고 비교해줍니다)

 

컴파일러에 의한 자동 해제 예제.

var complierOptional: Int? = 123
if complierOptional == 123{
    print("같다!")
}

 

그럼 다음에는 Optional Chaining도 알아볼게요!

 

 

 

 

출처

https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html



 

'공부 > iOS' 카테고리의 다른 글

iOS - UIKit  (0) 2020.07.07
iOS - Cocoa Touch Framework  (0) 2020.07.03
Swift - Optional(옵셔널) 기본  (0) 2020.06.23
Objective-C typedef에 대해서  (0) 2020.06.09
iOS 계층구조  (0) 2020.06.04