# Optional
---
## 질문
Optional 이란 무엇인지 설명하시오.
---
## 답변
## 팀원 이름
* `아리`, `예거`
### Optional 이란 무엇인지 설명하시오.
* `아리`
* 스위프트는 안전성을 중요시하는데요. 이 안정성의 기본 바탕에 있는 중요한 요소 중 하나가 바로 옵셔널입니다.
* 물음표 키워드를 사용하는 옵셔널은 변수의 값이 있을 수도 있고, 없을 수도 있다는 것을 뜻합니다.
* `예거`
- 상수나 변수의 메모리에 값이 없을 수도 있다는 것을 의미하기 위한 표현입니다. 기존 타입 뒤에 물음표(?)를 붙여서, **'옵셔널 타입'**을 선언할 수 있습니다.
- 값이 없음을 표현하기 위해 “nil” 이라는 단어를 사용합니다. (다른 언어에선 “null”)
- 메모리에 값이 없는 상수나 변수에 접근하게 되면 크래시가 나며, 앱이 강제 종료됩니다.
## `꼬리질문` 옵셔널은 무슨 역할을 하나요?
* `아리`
* 타입 캐스팅이나 nil 값 체크 등 값을 안전하게 가져올 수 있도록 중요한 역할을 합니다.
* `예거`
- 값이 없는 상수나 변수에 안전하게 접근할 수 있게 한 번 감싸주는(wrapping) 역할을 합니다.
## `꼬리질문` 옵셔널은 내부적으로 어떻게 구현되어 있나요?
* `아리`
* 옵셔널은 associated value를 가지는 열거형으로 구현되어 있습니다.
* 값이 존재할 때에는 some에 저장된 값을 반환하고, 값이 존재하지 않으면 nil을 반환합니다.
```swift
@frozen
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
```
* 여기서 @frozen 어트리뷰트는 더이상 케이스가 추가되지 않을 때 사용한다.
* Default 불필요함.
* `예거`
- **[코드 단계 설명]** 옵셔널은 case 가 2개(none, some(Wrapped))인 **열거형**과 **제네릭**으로 구현되어 있습니다.
- 열거형은 @frozen 어트리뷰트(attribute)가 붙어있으며, 이는 열거형에 case 가 더는 추가되지 않는다는 걸 말합니다.
- ⚠️ 스위프트에서 @키워드 붙은 거는 "attribute" 라고 부른다는 점에 주의하기! (어노테이션 아님!)
## `꼬리질문` 옵셔널의 값을 추출하려면 어떻게 해야할까요?
* `아리`
* 강제 추출, 옵셔널 바인딩, 암시적 추출이 있습니다.
* 강제 추출은 값이 있음을 확실할 수 있을 때 사용하는데요. 강제 추출을 시도 했는데 반환값이 nil일 경우 런타임 오류가 발생하기 때문에 보통은 사용을 지양하는 편입니다.
* 옵셔널 바인딩은 값이 있는지 안전하게 확인할 때 사용하며, guard문 혹은 if문이나 while문, switch문 등을 결합하여 사용합니다.
* 암시적 추출 옵셔널은 암묵적으로 벗겨진 옵셔널이라고 생각하면 되는데요. nil을 포함할 수 있는 옵셔널이긴 한데, 접근할 때 바인딩이나 옵셔널을 벗기는 과정을 거치지 않고도 바로 값에 접근할 수 있다는 점에서 일반적인 옵셔널과 조금 다릅니다. 만약 값이 없는데 접근을 시도하면 런타임 에러가 발생합니다.
* Nil coalescing을 활용해서 nil이 발생할 경우, 설정한 default 값을 반환하도록 하여 값을 추출할 수도 있습니다.
* `예거`
- 먼저, 옵셔널 타입을 강제로 언래핑하는 "**force unwrapping**"이 있습니다. 변수나 상수 뒤에 느낌표(!)를 붙여 사용합니다. 확실하게 nil 이 나오지 않는 경우가 아니라면 터부시됩니다. nil 인 값을 포스 언래핑하게 되면 앱이 강제 종료되기 때문입니다.
- 암시적 추출 옵셔널(Implicitly Unwrapped Optionals)도 있습니다.
- 어떤 옵셔널 타입의 상수나 변수가 있을 때, 런타임에서 nil 이 할당될 가능성이 없다고 판단한다면, 타입 뒤에 ? 대신 ! 를 입력해두면, 마치 Non-optional 타입 처럼 사용할 수 있습니다.
- UIKit + 스토리보드를 사용한 개발에서, 뷰컨과 스토리보드의 UI 컴포넌트를 연결할 때 생기는 **IBOutlet** 이 기본적으로 암시적 추출 옵셔널을 달고 생성됩니다.
- 그리고 많이 쓰는 **“옵셔널 바인딩”**이 있습니다. guard, if, while문 같은 조건문에서 사용할 수 있습니다.
```swift
var name: String? = "예거"
// 이런 일반적인 if-let 옵셔널 바인딩은
if let name = name {
print(name) // 예거
}
// 사실 이렇게 된 게 축약된 모습임 (제 해석이긴 해요;; 아리랑도 얘기해보고 싶었음)
if case .some(let name) = name {
print(name) // 예거
}
// 이렇게 사용할 수도 있음 -> Optional Pattern
if case let name? = name {
print(name) // 예거
}
// 출처: 소들이 블로그 -> https://babbab2.tistory.com/132
```
- **nil 병합 연산자(nil coalescing operator)**도 있습니다.
- 만약 nil 이 나온 경우 ‘대체해서' 넣어줄 수 있는 값을 지정할 수 있습니다. 코드가 짧으면서도 예외처리를 명확하게 할 수 있어서 아주 유용합니다.
- 좀 애매하지만, **옵셔널 체이닝**도 얘기해볼 수 있겠습니다. (언래핑한다기 보다는, 접근을 좀 편리하게 하기 위한 스킬 같음)
- 여러 겹의 옵셔널로 감싸진 값에 접근할 때, 하나하나 언래핑하면서 접근하면 가독성도 떨어지고 불편하겠죠.
- 그래서 옵셔널 타입인 상수나 변수 뒤에 물음표(?)를 붙인 뒤 dot(.)으로 접근할 수 있습니다. 이런 방식으로 여러 개를 이어 붙일 수 있어서 “체이닝"이란 말이 붙었습니다.
- 특징으로는, 옵셔널 체이닝에 마지막에 붙은 값은 옵셔널이 아니더라도, 무조건 옵셔널 타입으로 변환됩니다.
- (예시) university?.student?.name → 이런 식으로 옵셔널 체이닝을 사용할 수 있습니다.
- 만약 옵셔널 체이닝 과정에서 어디 한 곳이 nil 이 잡히게 된다면, 해당 코드는 작동하지 않고 넘어가게 되므로, 강제 종료가 되는 것보다는 안전하다고 말할 수 있습니다.
## `꼬리질문` 옵셔널 타입의 장단점을 설명해보세요.
* `아리`
* 장점은 값이 있을수도 없을수도 있는 상황에서 값을 안전하게 가져오거나, nil에 대한 예외처리가 강제된다는 점, 또 런타임에 nil에 대한 문제를 컴파일 단계에서 예방할 수 있다는 점입니다. 이러한 특징 때문에 Swift가 잠재적 오류에 대해 안전하다는 말도 있습니다.
* 단점은 옵셔널을 사용하게 되면 nil값을 가질 가능성이 항상 존재하기에 옵셔널을 사용하려면 바인딩 처리가 필수적입니다.
* `예거`
- **장점** : nil 에 대한 컴파일 에러를 통해, 개발자가 nil 이 발생하는 경우에 대한 **명확한 예외처리가 강제**되므로, 런타임에서 생길 수 있는 nil 로 인한 버그를 **컴파일 단계에서 예방**할 수 있습니다.
- **단점** : 발생할 가능성이 극히 낮은 경우에도, nil 이 나올 경우를 고민해야 하는 시간이 꽤 쓰이는 경험이 잦았습니다. 앱을 개발하면서 단 한 번도 보기 어려운 경우에 어떤 처리를 해줄 것인지 고민하는 시간이, 정말 의미있는 시간일지. 그 시간을 주요 기능 개발에 더 쓰는 게 낫지 않을까 고민한 적이 있습니다.
## `꼬리질문` guard-let과 if-let의 차이점이 무엇일까요?
* `아리`
* `if`나 `while`문은 스코프 내부에서 쓰기 위해 변수에 값을 넣었다면, guard문에서는 옵셔널 바인딩한 변수를 guard 구문 실행 후 지역 상수처럼 사용할 수 있습니다.
* 하지만 guard문은 else와 함께 쓰여 상위코드 블록을 종료하는 코드를 작성해야하므로 `예외사항을 처리해야할 때 사용`하면 좋습니다.
* `예거`
- 둘 다 옵셔널 값을 특정 상수에 binding(묶기) 하기 위해 자주 사용된다는 공통점이 있습니다.
- guard문은 메서드, 반복문 등 특정 블록 내부에서만 사용할 수 있고, guard문 뒤의 반드시 따라와야 하는 else 문 내부에서는 **반드시 return, throw 같은 ‘제어문 전환 명령'이 이뤄져야 합니다. (자신보다 상위 코드 블록을 종료하는 코드가 반드시 필요함.)** 예외상황 발생 시 어떤 마무리를 반드시 해줘야 하는 거죠. 그래서 로직이 조건에 맞지 않는다면, **빠른 종료(early-exit)**를 시키기 유용합니다.
- **guard-let 으로 바인딩한 상수**는 guard문을 벗어나서 메서드 내부의 **‘지역 상수'**처럼 사용할 수 있습니다.
- if문은 좀 더 광범위하게 사용할 수 있고, else문이 필수가 아닙니다, 따라서 return, throw 같은 제어문 전환 명령도 불필요합니다.
- **if-let 으로 바인딩한 상수**는 **해당 코드 블럭 안**에서만 사용할 수 있습니다. 중괄호 { } 를 벗어나면 호출이 안 됩니다. 즉, if-let 뒤에 따라 오는 else절에서 조차 호출할 수 없습니다.
## `꼬리질문` 옵셔널 체이닝에 대해서 설명해보세요.
* `아리`
* 여러 객체를 혼합해서 사용하다보면 옵셔널끼리 연산이 필요한 경우가 발생하는데요. 이때 객체마다 바인딩을 사용하게 되면 if문이 복잡해집니다. 따라서 옵셔널 체이닝은 이러한 상황에서 체이닝을 통해 값을 접근하여 간단하게 옵셔널 예외처리를 할 수 있습니다.
* 단, non-optional 타입을 체이닝으로 접근해도 optional 타입으로 반환됩니다. 앞서 접근했던 값은 optional하기 때문입니다.
* `예거`
## `꼬리질문` guard let은 왜 if let과 다르게 지역상수처럼 사용할 수 있을까요?
* `아리`
* guard의 경우 else구문이 필수적으로 같이 따라오는 점 때문인 것 같습니다. else문을 타게된다면 스코프 자체를 탈출하는 특성 때문에, if let과는 다르게 지역상수처럼 쓸 수 있는 것 같습니다.
* `예거`
- guard문에는 else절이 강제된다는 점이 차이를 만들어낸다고 생각합니다. if문은 else가 반드시 필요한 게 아니므로, if-let 옵셔널 바인딩이 '성공한다면' -> 중괄호 내부의 코드를 실행하는 것이고, 실패한 경우는 꼭 다루지 않아도 괜찮습니다.
- 반면, guard문은 else절을 반드시 붙여야 하니까, 옵셔널 바인딩이 '실패한 경우'에 대한 명확한 처리를 해둔 것이죠. 그 말은 guard문을 통과했다면, 옵셔널 바인딩이 '성공한 경우'로 판단할 수 있다는 것이고, 그 결과인 '옵셔널이 벗겨진 상수'를 메서드 내부에서 계속 사용할 수 있는 것입니다.
## `꼬리질문` guard var, if var 는 언제 쓸 수 있을까요?
* `아리`
* 바인딩 처리후 값을 수정해야할 때 사용될 것 같아요. 하지만 실제로는 변수보다는 상수로 처리하는 것을 선호해서 사용해본 적 없는 것 같아요.
* `개발자는 의도되지않은 변경에 조심해야한다.` 따라서 변수보다는 상수선언을 선호한다.
* `예거`
- var 는 변경할 수 있는 값인데, 개발자는 의도하지 않은 변경에 주의해야 한다. 만약 guard-var, if-var 를 써야 하는 상황이 온다면, 그건 오히려 코드를 잘못 설계했다는 반증이 아닐지.
---
## 팀원 이름 : 앨리, 애플사이다
### Optional 이란 무엇인지 설명하시오.
1. Optional이란 무엇인가요?
- Optional이란 “값이 없을 가능성”이 있는 상태를 말한다. nil의 가능성을 명시적으로 표현한다.
- 변수안에 값이 확실히 있다는 것을 보장할 수 없을 때 옵셔널을 쓴다.
2. Optional이 왜 필요한가요?
함수/이니셜라이저의 매개변수 타입, 함수의 반환타입 등에 사용된다.
함수/이니셜라이저에 해당 매개변수를 필수적으로 사용할 필요가 없는 경우 옵셔널 타입으로 지정한다.
함수의 내부처리 결과 적절한 값을 반환할 수 없는 경우 nil을 반환하고자 할 떄 옵셔널 타입으로 지정한다.
3. 그렇게 사용하는 장점은 무엇인가요?
위 상황에 대한 문서화/주석 작성 시간을 절약해준다.
또한 옵셔널이 없다면 매번 nil 체크를 하는 등 Unwrapping을 사용해야 하는데, 옵셔널이 있기 때문에 non-옵셔널 타입을 안심하고 사용 가능하다.
4. 옵셔널은 어떤 형태로 정의되어 있나요?
`제네릭이 적용된 열거형`으로 구현되어 있다.
따라서 switch문을 통해 nil 여부를 확인 가능하다. `case .none:`
```swift
@frozen
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
case none
case some(Wrapped) // The presence of a value, stored as `Wrapped`
}
```
5. (꼬리질문) frozen이라는 attribute는 무엇인가요?
열거형에 case가 추가되지 않을 것을 뜻함.
6. (꼬리질문) 제네릭은 무엇인가요? 언제 사용해봤나요?
실제 타입을 명시하지 않고, 플레이스홀더 타입 <T>을 통해 타입의 위치만 표시해두고,
호출하는 시점에 사용할 타입을 결정하게 한다.
타입 매개변수를 지정하면, 1) 함수의 매개변수 타입, 2) 반환 타입, 3) 함수 내부 변수의 타입을 지정할 때 사용할 수 있다.
Array, Dictionary, Set는 모두 제네릭 컬렉션이다.
Stack, Queue 등의 자료구조를 구현할 때도 제네릭을 사용한다.
7. 암시적 추출 옵셔널 `!`과 일반 옵셔널의 차이점은 무엇인가요?
필요 시 강제추출을 할 수 있는 옵셔널이다.
nil 할당이 가능한 non-옵셔널처럼 기능한다.
연산이 가능하며 (nil이 아닌 경우에만), 동시에 unwrapping 및 강제추출이 가능하다.
강제추출과 마찬가지로 로직상 nil 발생 가능성이 없다고 확신할 때만 사용해야 한다.
IBOutlet 변수의 default 타입이다.
8. Unwarpping을 해야하는 상황은?
옵셔널 값을 옵셔널이 아닌 변수 등에 할당할 때, 또는 연산할 때, 필요하다.
9. Unwarpping 방법 4개를 설명하고, 안전성에 대해 설명하시오.
- Optional binding
if-let, guard-let, switch문, while문을 통해 nil 체크를 한다. nil이면 변수/상수에 할당되지 않게 한다.
- Optional Chaining
postfix ?를 사용하여 nil 체크를 한다. 하위 프로퍼티에 옵셔널 값이 있는지 연속적으로 확인하면서 중간에 하나라도 nil이 발견된다면 nil을 반환한다.
- Nil-Coalescing Operator (nil 병합 연산자)
??를 사용하여 nil인 경우 사용할 기본값을 지정한다. 연쇄적으로 사용 가능
- Unconditional unwrapping
옵셔널 변수 뒤에 !를 붙인다. 값이 있음을 가정하고 해당 값에 바로 접근한다.
로직상 nil 발생 가능성이 없다고 확신할 때만 사용해야 한다.
강제로 추출하는 Unconditional Unwrapping 외에는 모두 안전하다.
10. (꼬리질문) if-let과 guard-let의 차이는 뭘까요?
- 해당 scope가 끝나면 쓸수 없음, 쓸수 있음
- guard 문은 지켜야 하는 원칙이 있을 때 사용
11. nil이 할당된 옵셔널을 Unconditional unwrapping하면 무슨 일이 발생하나요?
런타임 에러 발생
12. 옵셔널 및 non-옵셔널의 값이 동일한지 비교하려면 어떻게 하나요? 타입이 다른데 어떻게 비교할 수 있나요?
`==` 연산자, `!=` 연산자 사용
Swift GitHub 문서를 보면, 값이 옵셔널 타입인 경우 swift문을 통해 자동으로 언래핑하도록 구현되어 있다.
코드 : [https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift](https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift)