Featured image of post 옵셔널 (Optional)

옵셔널 (Optional)

Optional - 값이 있을 수도 있고 없을 수도 있음을 의미.

변수명 뒤에 ?를 붙여서 옵셔널을 선언해줌. Optional<String>으로 표현해줄 수도 있음.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// non-optional
var name: String = "Jae"
name = nil // Error

// optional
var name: String? = "Jae"
print(name) // Optional("Jae")

name = nil
print(name) // nil

Swift에서 옵셔널의 정의

➡️ 옵셔널은 열거형으로 정의되어 있고, nil일 경우에는 none 케이스가 될 것이고, 값이 있을 때는 some 케이스가 되게 된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)

    public init(_ some: Wrapped)
    ...

}

Unwrapping 언래핑

optional String 타입의 변수 name을 출력해보면 Optional("Jae")와 같이 출력되기 때문에 자료형을 사용하기 위해서는 Optional에서 값을 꺼내와야 한다. 이것을 Unwrapping 이라고 부른다.

‼️ unwarpping 하고자 하는 값이 nil이면 언래핑을 할 수 없다.

img

Forced Unwrapping 강제추출

무조건 변수가 있는 상황이 보장된다면 뒤에 느낌표!를 붙여서 강제추출을 할 수 있다.

1
2
3
4
5
6
var name: String? = "Jae"
print(name!) // Jae

// 사용자 입력을 받는 `ReadLine` 함수에서 이렇게 사용하기도 한다.
// 가장 간단한 방법이지만, 가장 위험한 방법이기 때문에 되도록이면 사용하지 않는 것이 좋다.
name = Readline()!

Optional Binding 옵셔널 바인딩

값이 nil인지 확인하고 값이 있으면 값을 언래핑하는 방법을 Optional Binding 이라고 부른다.
if letlet var를 사용한다.

- if let

img

if문 안의 조건문이 nil인지 아닌지를 체크하고 nil이 아니라면 해당 블럭이 실행된다.

1
2
3
4
5
6
7
var name: String? = "Jae"

if let name = name {
    print(name)
} else {
    print("name is nil")
}

name 값을 가지고 있는 경우 이름이 출력되고, name이 nil인 경우 “name is nil"이 출력된다.

- guard let

img

guard 조건문이 참이 아니면 else 문이 실행되는 문법이다. else문 안에는 코드 블럭을 종료하는 continue, break, return, throw를 반드시 사용해야 한다.

‼️ guard let 으로 선언한 상수는 guard문 밖에서도 사용이 가능하다.

1
2
3
4
5
6
7
var name: String? = "Jae"

guard let name = name  else {
    print("name is nil")
    return
}
print(name)

Nil Coalescing Operator - nil 병합 연산

값이 없는 경우 기본 타입 변수를 지정해주는 방식

1
2
var name: String? = "Jae"
print("userName : \(name ?? "Stranger")")

name이 있는 경우에는 이름이 출력되고, name이 nil인 경우애는 Stranger가 출력된다.

조건 연산자를 이용하는 것도 가능하다.

1
2
3
4
5
var name: String? = "Jae"
var displayName = "Hello, " + (name != nil ? name! : "Stranger")

var displayName = "Hello, " + (name ?? "Stranger") //same as above
print(displayName)

Optional Chaining - 옵셔널 체이닝

옵셔널을 연달아 호출하기

  • Optional Chaining의 결과는 항상 Optional이다.

  • Optional Chaining 중 하나라도 nil값이 있다면 이후 표현식은 체크하지 않고 바로 nil을 리턴한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 옵셔널 체이닝을 사용하지 않는다면...
func guardJob(owner: Person?) {
    if let owner = owner {
        if let home = owner.home {
            if let `guard` = home.guard {
                if let guardJob = `guard`.job {
                    print("우리집 경비원의 직업은 \(guardJob)입니다")
                } else {
                    print("우리집 경비원은 직업이 없어요")
                }
            }
        }
    }
}
guardJob(owner: yagom)

// 옵셔널 체이닝을 사용한다면
func guardJobWithOptionalChaining(owner: Person?) {
    if let guardJob = owner?.home?.guard?.job {
        print("우리집 경비원의 직업은 \(guardJob)입니다")
    } else {
        print("우리집 경비원은 직업이 없어요")
    }
}
guardJobWithOptionalChaining(owner: yagom)