The Basics - Optionals Swift


옵셔널

값이 없을 수도 있을 때 옵셔널을 사용한다. 옵셔널은 두가지 가능성을 표현하는데, 값이 있고 해당값에 접근가능한 상황과 아예 값이 없는 상황이다.

일러두기)
옵셔널의 개념은 C또는 오브젝티브 C에 없는 것으로서 가장 근접한 것은 닐 객체로부터 메소드를 호출하는 오브젝티브C를 예로 들 수 있다. 그러나 이 것은 객체만 작동하지 구조체, 기본 C형식 또는 열거형에서는 작동하지 않는다. 이런 형식에 대해 대응하기 위해 오브젝티브 C는 NSNotFound와 같은 특별한 값을 반환한다. 이런 접근은 메소드의 호출자가 이 특별한 값을 알고 적절한 대응을 해야 함을 나타낸다. 스위프트의 옵션널은 형식에 제한이 없으며 특별한 상수값도 알아야할 필요가 없게 해준다.

Here’s an example of how optionals can be used to cope with the absence of a value. Swift’s Int type has an initializer which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" doesn’t have an obvious numeric value to convert to.

아래의 예시에서 문자열을 숫자로 컨버트하는데 생성자를 사용하고 있다.

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"

생성자가 실패할 수 도 있으므로 옵셔널 Int 를 리턴한다. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.)

nil

You set an optional variable to a valueless state by assigning it the special value nil:

var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value

일러두기)
You can’t use nil with nonoptional constants and variables. If a constant or variable in your code needs to work with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type.

If you define an optional variable without providing a default value, the variable is automatically set to nil for you:

var surveyAnswer: String?
// surveyAnswer is automatically set to nil

일러두기)
스위프트의 닐은 오브젝티브C와 같지 않다. 오브젝티브C에서는 존재하지 않는 객체에 대한 포인터이지만, 스위프트에서 닐은 포인터가 아닌 형식값의 부재이다. 옵셔널은 객체 형식과 상관없이 어떤 형식이든 닐을 할당할 수 있기 때문이다.

if 와 강제된 언랩

if 를 사용해 옵셔널이 값을 가졌는지여부를 확인할 수 있다. 이는 == 또는 != 로 수행한다.

만약 옵셔널이 값을 가지면 닐이 아니라 생각할 수 있다.

if convertedNumber != nil {
  print("convertedNumber contains some integer value.")
}

일단 옵셔널이 반드시 값을 가진다고 보면 값을 !로 접근할 수 있다. !는 옵셔널은 반드시 값을 가진다 나는 사용하겠다를 나타낸다. 이를 옵셔널에 대한 강제된 업랩이라 한다.

if convertedNumber != nil {
  print("convertedNumber has an integer value of \(convertedNumber!).")
}

For more about the if statement, see Control Flow.

일러두기)
Trying to use ! to access a nonexistent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.

옵셔널 바인딩

옵셔널 바인딩을 사용해 옵셔널이 값을 가지는지 확인하고 만약 그렇다면 임시 상수나 변수로 만들 수 있다. 옵셔널 바인딩은 if 와 while 에서 옵셔널 내의 값을 확인하는데 사용하고 단일 액션이 가능하게 상수나 변수로 값을 뽑아낸다.  if and while statements are described in more detail in Control Flow.
if 문장에 대한 옵셔널 바인딩은 다음과 같다

  1. if let constantName = someOptional {
  2. statements
  3. }

옵셔널 섹션에서 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 the optional Int returned by Int(possibleNumber) contains a value, set a new constant called actualNumber to the value contained in the optional.”

If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there’s no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion.

상수나 변수에서 옵셔널 바인딩을 사용할 수 있다. actualNumber 의 값을 첫 브랜치에서 수정하고 싮다면 if var actualNumber 를 대신 사용할 수 있는데 옵셔널 내의 값이 상수가 아닌 변수로 전달된다.

단일 if 문에 여러 옵셔널 바인딩과 불린을 조합할 수 있으며 콤마로 구별한다. 만약 옵셔널 바인딩의 어떤 것이든 닐이거나 불린이 거짓이면 if 문의 조건은 거짓으로 판단한다. 다음  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"

일러두기)
Constants and variables created with optional binding in an if statement are available only within the body of the if statement. In contrast, the constants and variables created with a guard statement are available in the lines of code that follow the guard statement, as described in Early Exit.

내포적 언랩된 옵셔널

As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.

Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.

These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.

Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties.

An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it’s accessed. The following example shows the difference in behavior between an optional string and an implicitly unwrapped optional string when accessing their wrapped value as an explicit String:

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

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

You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it’s used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it.

일러두기)
If an implicitly unwrapped optional is nil and you try to access its wrapped value, you’ll trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that doesn’t contain a value.

ou can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:

if assumedString != nil {
    print(assumedString!)
}
// Prints "An implicitly unwrapped optional string."
You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement:

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

일러두기)
Don’t use an implicitly unwrapped optional when there’s a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable.



덧글

댓글 입력 영역