Where who wants to meet someone

[1주차] 1. Optional이란 무엇인지 설명하시오 본문

Apple Developer/면접 스터디

[1주차] 1. Optional이란 무엇인지 설명하시오

Lust3r 2023. 7. 1. 23:55
728x90

  1. Optional이란 무엇인지 설명하시오.
  2. KVO 동작 방식에 대해 설명하시오.
  3. stackView의 장점과 단점에 대해서 설명하시오.

1. Optional이란 무엇인지 설명하시오.

Optional | Apple Developer Documentation

 

Optional | Apple Developer Documentation

A type that represents either a wrapped value or the absence of a value.

developer.apple.com

 - 래핑 된 값 또는 값이 없음을 나타내는 형식

OverView

- Optional이라는 단어를 입력하지 않더라도 Optional value를 사용할 때마다 이 유형을 사용함.

- Swift의 유형 시스템은 일반적으로 전체 유형 이름을 표시하는 대신 후행 물음표와 함께 래핑 된 유형의 이름을 표시함
   예를 들어 변수에 Int? 유형이 있는 경우 이는 Optional을 작성하는 또 다른 방법일 뿐임.
   코드를 쉽게 읽고 쓸 수 있도록 축약형이 선호됨.

 

- 축약형과 아닌 것의 예제는 아래 참고

let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")

- Optional 유형은 두 개의 케이스를 가진 열거형임.
   Optional.nonenil 과 동일하고, Optional.some(Wrapped)래핑 된 값을 저장한다.
   예를 들어

let number: Int? = Optional.some(42)
let noNumber: Int? = Optional.none
print(noNumber == nil)
// Prints "true"

 

- 여러 context에서 사용하려면 먼저 Optional 인스턴스의 값을 언래핑해야 함.

- Swift는 Optional 값을 안전하게 언래핑하는 여러 가지 방법을 제공하므로 명확하고 간결한 코드를 작성하는 데 도움이 되는 방법을 선택할 수 있음.

 

- 다음 코드 예제는 이미지 이름 및 파일 경로 dictionary를 사용하는 것.

let imagePaths = ["star": "/glyphs/star.png",
                  "portrait": "/images/content/portrait.jpg",
                  "spacer": "/images/shared/spacer.gif"]

- 키를 사용하여 dictionary의 값을 가져오면 Optional 값이 반환되므로 imagePaths["star"]는 Optional<String> 또는 선호하는 방식으로 작성된 String? 유형을 갖는다.


→ Why? dictionary에서 키를 사용하여 값을 가져오면 왜 Optional 값이 반환될까?

Dictionary | Apple Developer Documentation

 

Dictionary | Apple Developer Documentation

A collection whose elements are key-value pairs.

developer.apple.com

Getting and Setting Dictionary Values 를 참조하면

키가 있는 Dictionary를 첨자화하면 Optional 값이 반환된다고 한다.

왜냐하면 첨자에서 사용하는 key에 대한 값을 보유하지 않을 수 있기 때문이다.

var responseMessages = [200: "OK",
                        403: "Access forbidden",
                        404: "File not found",
                        500: "Internal server error"]

let httpResponseCodes = [200, 403, 301]
for code in httpResponseCodes {
    if let message = responseMessages[code] {
        print("Response \(code): \(message)")
    } else {
        print("Unknown response \(code)")
    }
}
// Prints "Response 200: OK"
// Prints "Response 403: Access forbidden"
// Prints "Unknown response 301"

위 예제 코드를 보면, httpResponseCodes의 값을 가지고 for문을 돌면서 그 값을 키로 갖는 값이 있다면 if let 안의 print문을 출력, 없다면 else로 빠지는 구조로 되어 있다.

200과 403은 responseMessages에 있지만 301은 없는 키 값이기에 else로 빠짐을 볼 수 있는데,

이처럼 Dictionary의 값을 얻을 때 키값을 첨자화해서 넣게 되면 그 값이 있을지 없을지 모르기 때문에 Optional 값을 반환하는 것이다.

 

Optional Binding

Optional 인스턴스의 래핑된 값을 새 변수에 조건부로 바인딩하려면 if let, guard let 및 switch를 포함하여 optional 바인딩 제어 구조 중 하나를 사용해야 한다.

if let starPath = imagePaths["star"] {
    print("The star image is at '\(starPath)'")
} else {
    print("Couldn't find the star image")
}
// Prints "The star image is at '/glyphs/star.png'"

Optional Chaining

래핑된 인스턴스의 속성과 메서드에 안전하게 접근하려면 접미사 optional chaining operator인 ?를 사용해야 한다.

다음 예제는 이러한 Optional chaining을 사용하여 String? 인스턴스의 hasSuffix(_:) 메서드에 접근한다.

if imagePaths["star"]?.hasSuffix(".png") == true {
    print("The star image is in PNG format")
}
// Prints "The star image is in PNG format"

코드 첫 줄을 보면 imagePaths["star"]는 Optional Value이기 때문에 postfix chaining operator인 ?를 붙여주는 것을 볼 수 있다.

Using the Nil-Coalescing Operator

Optional 인스턴스가 nil인 경우 nil 병합 연산자(??)를 사용하여 기본값을 제공할 수 있다.

let defaultImagePath = "/images/default.png"
let heartPath = imagePaths["heart"] ?? defaultImagePath
print(heartPath)
// Prints "/images/default.png"

위의 예제를 보면, heartPath에서 imagePaths의 "heart"키에 대한 값을 할당하고자 하나, 없을 수 있으므로 그럴 때 할당하기 위한 기본값 defaultImagePath를 ?? 연산자 뒤에 붙인 것을 확인할 수 있다.

 

실제로 print로 heartPath를 출력해봤을 때, defaultImagePath의 값이 나온 것으로 보아 "heart"의 값이 없었음을 알 수 있다.

 

?? 연산자는 오른쪽에 있는 다른 Optional 인스턴스와도 작동하기 때문에 여러 ?? 연산자를 연결할 수 있다.

let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultImagePath
print(shapePath)
// Prints "/images/default.png"

위의 예제에서는 imagePaths["cir"]의 값을 할당하고자 하나 없을 경우 ?? 연산자를 통해 다른 값으로 imagePaths["squ"]를 주고자 한다. 하지만 그마저도 없을 수 있으므로 ?? 연산자를 추가로 붙여 defaultImagePath를 확실한 기본값으로 넣어주었다.

Unconditional Unwrapping

Optional 인스턴스에 값이 포함되어 있다고 확신하는 경우 강제 언래핑 연산자인 !를 사용하여 무조건 값을 언래핑할 수 있다.

let number = Int("42")!
print(number)
// Prints "42"

언래핑 뿐만 아니라 이전에 Optional 값의 속성에 접근하기 위해 ?를 사용했었는데, 여기에도 !를 사용해서 접근할 수 있다.

let isPNG = imagePaths["star"]!.hasSuffix(".png")
print(isPNG)
// Prints "true"

하지만 이는 값이 확실하게 포함되어 있을 때 사용해야 하며, nil 인스턴스를 강제 언래핑을 하게 되면 런타임 오류를 발생시킨다.

 

1-1. Optional이란 무엇인지 설명하시오. (질문)

Q. Swift에서 옵셔널이 무엇인지 간략하게 설명해주실 수 있나요?

A. Swift에서 옵셔널은 값이 있을 수도 있고 없을 수도 있는 변수 또는 상수를 나타내는 타입. 없으면 nil을 가짐

 

Q. 그렇다면 어떤 상황에서 유용하게 사용할 수 있을까요?

A. 사용자의 입력을 받는 경우 등 주로 값이 없을 수 있는 변수 또는 상수를 다룰 때 유용함. 또한 외부 API 호출 결과나 파일 로딩 등에서도 옵셔널을 사용하여 값의 유무를 체크하고 안전하게 처리할 수 있음

 

Q. 사용해본적이 있나요? 있다면 언제 써봤나요?

 

Q. 안전하게 처리할 수 있다고 했는데, 옵셔널 값을 처리하는 방법에는 어떤 것이 있을까요?

A. 옵셔널 바인딩, 강제 언래핑, 옵셔널 체이닝 등이 있음.

 

Q. 각 방법에 대해서 간략하게 설명해주세요

A. 옵셔널 바인딩은 if let 또는 guard 구문을 사용하여 nil인지 확인하고 안전하게 값을 추출하는 방법

강제 언래핑은 !를 사용하여 강제로 추출하는 방법으로, 값이 nil인 경우 런타임 에러가 발생할 수 있으므로 주의해야 함

옵셔널 체이닝은 옵셔널 값이 연속적으로 연결된 상황에서 각 옵셔널 값이 nil이 아닌지 체크하고 아닐 때만 다음 값으로 넘어가는 방법임