Optional
이란?You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all.
우리는 값이 없는 상황에서(비어있는 값을 표현하고자 할 때) Optional
을 사용합니다. 옵셔널은 두가지 가능성을 의미합니다: 값이 있고, 해당 값에 접근하기 위해 옵셔널을 벗길(unwrap) 수 있는 경우와 값이 없는 경우입니다.
쉽게 말해 값이 있을수도 있고, 없을 수도 있다.
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber는 "Int?", 혹은 "optional Int" 타입으로 추론됩니다.
print(type(of: convertedNumber)) //Optional<Int>
print(convertedNumber) //Optional(123)
Int
타입에는 String
타입의 값을 Int
타입의 값으로 변환하려는 이니셜라이저가 있다. 하지만 항상 초기화에 성공하는 것은 아니다. 위 예제에서 possibleNumber
라는 상수의 값이 123
이 아닌 Hello
와 같은 숫자가 아닌 값이라면 possibleNumber
라는 상수의 타입은 Int
타입이 될 수 없다.let possibleNumber = "Hello"
let convertedNumber = Int(possibleNumber)
// possibleNumber의 값이 숫자가 아닌 문자이므로 Int타입의 이니셜라이저가 초기화에 실패하였다.
print(type(of: convertedNumber)) //Optional<Int>
print(convertedNumber) //nil
Int
타입으로 초기화를 실패할 경우 Swift에선 바로 런타임 에러를 뿜어내지 않고 이 값을 nil
로 할당하여 오류를 방지한다.nil
값이 할당된 convertedNumber
의 타입을 옵셔널로 감싸진 Int타입, 즉 Optional<Int>
타입이라고 한다. Optional<Int>
타입은 코드상에서 Int?
로 작성된다. 이 물음표가 붙은 타입에 포함된 값이 있을 수도 있고 없을 수도 있다. 당연히 값이 있다면 Int
타입의 값만 있을 수 있다.Optional
의 선언let name: String? = nil
타입 추론을 사용하는 방법은 한가지 조건이 필요하다. 바로 “초기화 되는 값이 무조건 옵셔널 자료형” 이어야만 한다.
이는 타입 추론을 알고 있다면 당연히 이해가 될 것이다.
let a: Int? = nil
let b = a // b = nil
var age = nil // age가 어떤 타입의 옵셔널타입인지 추론 불가능.
위 예제를 보면 알수 있듯, 타입 추론을 통해 nil로 타입 추론을 시도하면 에러가 뜬다.
컴파일러는 저 nil
만 보고 변수 age
의 알맞은 타입을 할당해야 하는데, nil
은 말 그대로 없는 값이므로 타입을 유추할 수 없는것이다.
You set an optional variable to a valueless state by assigning it the special value
nil
:
nil
을 할당하여 값이 없는 상태로 설정합니다.var serverResponseCode: Int? = 404
// serverResponseCode변수는 실제 Int타입의 값인 404가 포함되어 있습니다.
serverResponseCode = nil
// serverResponseCode는 이제 값이 없습니다.
nil
을 할당한다.var surveyAnswer: String?
// surveyAnswer 변수에 자동으로 nil이 할당됩니다.
You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with
if
andwhile
statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action.
우리는 옵셔널 바인딩을 통해 값에 옵셔널 값이 포함되어 있는지 확인하고, 포함된 경우 해당 값을 임시 상수 또는 변수로 사용할 수 있도록 할 수 있습니다. 옵셔널 바인딩은 if
및 while
문과 함께 사용하여 옵셔널 값의 내부를 확인하고 단일 작업의 일부로 해당 값을 상수 또는 변수로 추출할 수 있습니다.
if
문에 옵셔널 바인딩을 작성하는 방법은 다음과 같다.
if let constantName = someOptional {
statements
}
let possibleNumber = "123"
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"
이 코드는 다음 과 같이 읽을 수 있다.
- 만약, Int(possibleNumber)
가 반환하는 옵셔널Int
타입에 값이 포함된 경우, actualNumber
라는 새 상수를 옵셔널 안에 있는 값으로 선언한다.
변환에 성공하면 조건문 안에서만 실제 숫자 상수를 사용할 수 있다. 이때 옵셔널 내부의 값으로 이미 초기화 되었으므로, ! 접미사를 사용하여 옵셔널을 강제로 추출할 필요가 없다.
let
대신 var
를 사용하여 이러한 옵셔널 값을 변수로 사용도 가능하다.
만약 옵셔널 내부의 포함된 값을 새 상수에 선언한 후 이전 옵셔널 타입의 상수 또는 변수를 다시 참조할 필요가 없는 경우, 새 상수 또는 변수의 이름을 동일한 이름으로 사용할 수 있다.
let myNumber = Int(possibleNumber)
// 여기서, myNumber는 옵셔널 Int입니다.
if let myNumber = myNumber {
// 여기서, myNumber는 논-옵셔널 Int입니다.
print("My number is \(myNumber)")
}
// Prints "My number is 123"
if let myNumber {
print("My number is \(myNumber)")
}
// Prints "My number is 123"
if let
대신 if var
도 사용 가능하다. if var
를 통해 선언된 새 변수의 값을 변경할 경우, 기존에 있던 옵셔널 상수 또는 변수에 영향을 주지 않고 해당 로컬 변수에만 적용된다.
단, 이 변화는 개체 내부의 속성으로 확장되지는 않는다.
struct User {
var name: String
}
let user: User? = User(name: "Wonbi")
if let user.name { // Error!
print("Welcome, \(user.name)!")
}
if
문에 옵셔널 바인딩을 포함해 여타 다른 참거짓 조건을 추가할 수 있다.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"
nil
이거나 참거짓 조건이 false
라면, 전체 if
문이 거짓인 것으로 고려된다.if
문안에서만 사용이 가능하다. 하지만 guard
문을 통해 생성된 변수와 상수는 guard
문 이후의 코드라인에서도 사용가능하다. 옵셔널 바인딩 이후의 action에 대한 코드가 길어진다면 guard 문을 사용하자.
우와! 정말 잘 읽고 갑니다!