Swift 뿌수기 - Optional

Wonbi·2022년 8월 16일
3

Swift 뿌수기

목록 보기
2/12

✅학습 내용

💎 Optional

✏️ 1. 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타입의 값만 있을 수 있다.

✏️ 2. Optional의 선언

  • 옵셔널 타입을 선언하는 방법은 두가지가 있다.
    1. 타입 어노테이션을 사용하는 방법
    2. 타입 추론을 이용한 방법

1. 타입 어노테이션

  • 타입 어노테이션을 사용하는 방법은 간단하다. 위에 설명한 것처럼 타입을 선언할 때 뒤에 ?를 붙여주면 된다.
let name: String? = nil

2. 타입 추론

  • 타입 추론을 사용하는 방법은 한가지 조건이 필요하다. 바로 “초기화 되는 값이 무조건 옵셔널 자료형” 이어야만 한다.

  • 이는 타입 추론을 알고 있다면 당연히 이해가 될 것이다.

let a: Int? = nil
let b = a		// b = nil

var age = nil	// age가 어떤 타입의 옵셔널타입인지 추론 불가능.
  • 위 예제를 보면 알수 있듯, 타입 추론을 통해 nil로 타입 추론을 시도하면 에러가 뜬다.

  • 컴파일러는 저 nil 만 보고 변수 age 의 알맞은 타입을 할당해야 하는데, nil은 말 그대로 없는 값이므로 타입을 유추할 수 없는것이다.

💎 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이 할당됩니다.

💎 Optional Binding

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 and while 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.

  • 우리는 옵셔널 바인딩을 통해 값에 옵셔널 값이 포함되어 있는지 확인하고, 포함된 경우 해당 값을 임시 상수 또는 변수로 사용할 수 있도록 할 수 있습니다. 옵셔널 바인딩은 ifwhile문과 함께 사용하여 옵셔널 값의 내부를 확인하고 단일 작업의 일부로 해당 값을 상수 또는 변수로 추출할 수 있습니다.

  • 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"

💡 요기서부터 Swift 5.7에서 추가된 신기능!

  • 위 예제와 같은 종류의 코드는 매우 일반적이므로, 더 짧게 줄여서 사용할 수 있다. 즉, 옵셔널 바인딩 하려는 상수 또는 변수의 이름만 작성하여 값을 바인딩 할 수 있다. 새로 추가된 상수 또는 변수(옵셔널이 벗겨진 상수 혹은 변수)는 옵셔널 값과 동일한 이름을 암시적으로 사용한다.
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 문을 사용하자.

1개의 댓글

comment-user-thumbnail
2022년 9월 1일

우와! 정말 잘 읽고 갑니다!

답글 달기