Optional

윤주현·2023년 6월 30일

Swift

목록 보기
2/13

Optional

// 일반 Int 타입
let number1: Int = Int(42)
let number2: Int = 42
let number3 = 42

// 옵셔널 Int
let possibleNumber: Int? = 42

옵셔널은 nil값을 처리하기 위해 사용하고 변수의 값이 있는지 없는지를 나타낼 수 있는 타입이다.

옵셔널은 열거형(enum)이다!

프로그래밍 언어를 사용하면서 가장 성가신 문제 중 하나는 변수의 값이 null/nil인지 아닌지 if문을 사용해서 일일이 확인을 해야한다. 하지만 스위프트는 옵셔널 타입을 통해서 nil의 여부를 간단하고 안전하게 체크할 수 있다.

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber의 타입은 옵셔널 Int

위의 코드는 String타입의 possibleNumber를 Int로 변환하여 covertedNumber에 할당했다. String을 Int로 변환하는 과정에서 에러가 생길 수도 있기 때문에 스위프트는 값을 옵셔널로 처리하여 할당한다. 옵셔널 타입의 값을 사용하기 위해서는 언래핑(unwrapping)을 해야한다. 언래핑을 하는 방법은 4가지가 있다.

Optional Binding

if, guard, switch문을 사용하는 방법이다.

let possibleNumber: Int? = 42

if let number = possibleNumber {
    print("We have a number \(number)!")
} else {
    print("Sorry. No soup for you.")
}

func printNumber(possibleNumber: Int?) {

    guard let number = possibleNumber else {
        print("No number here.")
        return
    }

    print("We have a number \(number)!")
}

위의 코드는 possibleNumber를 if문과 guard문을 이용해 옵셔널 바인딩을 하여 언래핑된 number라는 변수로 사용하는 것을 보여준다. possibleNumber가 nil이었다면 "Sorry. No soup for you."가 출력되었겠지만 possibleNumber에는 옵셔널 42가 저장되어 있으므로 "We have a number 42!"가 출력된다.

if vs guard

if let x = someOptional {
	// use unwrapped x
} else {
	// x is nil
}

guard let x = someOptional {
	// leave scope
}
// use unwrapped x

if문은 옵셔널 값이 nil인 경우에도 처리하고 싶은 동작이 있을때 사용하고 guard문은 파라미터로 옵셔널 값을 받는 함수가 있다고 할 때 함수 안에서 처음에 guard문을 이용해 언래핑을 해주면 옵셔널 값이 nil일경우 함수를 일찍 리턴시킬 수 있다.(if보단 guard를 더 많이 사용한다.)

Forced Unwrapping

옵셔널 값을 강제로 언래핑을 하는 방법이다. 값이 있다고 확신하는 경우에만 사용하고 옵셔널 값의 끝에 느낌표(!)를 붙여서 사용한다.

let possibleNumber: Int? = 42
let number = possibleNumber! // Yay ✅

//var possibleNumber: Int?
//let number = possibleNumber! // Boom 💥

Nil-Coalescing Operator

옵셔널 값을 사용할수 있게 default값을 지정해 주는 방법이다. 값이 nil이라면 default값을 사용하고 값이 있다면 그 값을 사용한다. 다음과 같이 물음표 2개(??)를 붙여서 사용한다.

let nickName: String? = nil
let defaultName: String = "John"
let imformalGreeting = "Hi \(nickName ?? defaultName)"
// "Hi John"

nickName의 값이 nil이기 때문에 default값으로 지정한 defaultName의 값을 사용하여 "Hi John"이 출력되었다.

Optional Chaining

점 표기법을 사용할 때 중간에 옵셔널 값을 처리하기 위해 사용하는 방법. 옵셔널 값이 nil이라면 코드는 동작하지 않을 것이고 값이 있을 경우에만 동작하고 결과 값은 옵셔널 값으로 리턴된다.

class Person {
	var residence: Residence?
}

class Residence {
	var numberOfRooms = 1
}

let john = Person()
// let roomCount = john.residence!.numberOfRooms // runtime error Boom 💥
if let roomCount = john.residence?.numberOfRooms {
	print("John's residence has \(roomCount) room(s).")
} else {
	print("Unable to retrieve the number of rooms.")
}    
// "Unable to retrieve the number of rooms."

Implicitly Unwrapped Optionals

옵셔널이 항상 값이 있을거라고 예상될 때 Implicitly Unwrapped Optional을 사용한다. Implicitly Unwrapped Optional은 타입명 끝에 !를 붙여서 지정할 수 있다. 스위프트에서 Implicitly Unwrapped Optional은 옵셔널처럼 취급되지만 항상 값이 있을거라고 예상되기 때문에 언래핑 하지 않고도 옵셔널 값이 아닌 일반적인 값을 얻을 수 있다.

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

위와 같이 옵셔널 타입인 possibleString으로부터 일반 String 타입을 가지고 있는 forcedString에 값을 넣으려면 언래핑을 해주어야 하지만 Implicitly Unwrapped Optional을 사용했을 때는 언래핑을 하지 않고도 에러 없이 값을 전달해 줄 수 있다는 것을 알 수 있다.

하지만 Implicitly Unwrapped Optional이 항상 값을 언래핑 하는 것은 아니다. 위와 같은 경우 implicitString의 타입이 일반적인 String타입이었기 때문에 언래핑이 된것이다. Implicitly Unwrapped Optionals는 처음엔 평범한 옵셔널 값처럼 사용하는 것을 시도하고 만약 옵셔널로 사용할 수 없다면 그때 값을 강제로 언래핑한다.

let optionalString: String?
let assumedString: String! = "An implicitly unwrapped optional string."

optionalString = assumedString
print(optionalString) // Optional("An implicitly unwrapped optional string.")
print(assumedString) // Optional("An implicitly unwrapped optional string.")

위와 같이 옵셔널 String 타입에 Implicitly Unwrapped Optional String 타입의 값을 전달했을 때는 언래핑을 하지 않고 옵셔널 타입으로 전달한다. 기본적으로 Implicitly Unwrapped Optional도 옵셔널 타입이기 때문에 물론 if문이나 옵셔널 바인딩을 사용하여 nil값을 체크할 수 있다.

Tip

  • 객체를 생성할 때 값이 없는 경우에 옵셔널을 사용하고 옵셔널이 필요한 경우가 아니라면 일반 타입의 값을 사용하는 것이 더 쉽다.
  • 옵셔널 값을 언래핑 할때는 초반에 해서 코드를 알아보기 쉽게 하는 것이 좋다.

0개의 댓글