Optional이란 무엇인지 설명하시오.
2022. 5. 8. 12:45ㆍSwift/기술 면접
옵셔널(Optional)이란?
값이 있을수도 있고, 없을수도 있음을 표현
let optionalConstant : Int? = nil
// 옵셔널이 아닌 상수에 nil값을 할당하려고 하면
// 컴파일 오류 발생
// let someConstant : Int = nil
nil이할당될 수있는지 없는지표현
// someOptionalParam에는 nil이 할당 될 수 있다.
func someFunction(someOptionalParam:Int?) {
// ...
}
// someParam에는 nil이 할당 될 수 없다.
func someFunction(someParam:Int) {
// ...
}
someFunction(someOptionalParam:nil)
// someFunction(someParam:nil)
옵셔널을 사용하는 이유
- 명시적 표현
- nil의 가능성을 코드만으로 표현 가능
- 문서/주석 작성 시간 절약
- 안전한 사용
- 전달받은 값이 옵셔널이 아니라면 nil체크를 하지 않고 사용가능
- 예외 상황을 최소화하는 안전한 코딩
- 효율적인 코딩
옵셔널 문법과 선언
- 옵셔널 문법
enum + generics
- 옵셔널 선언
enum Optional<Wrapped> : ExpressibleByNiliteral {
case none // 옵셔널에 값이 없다.
case some(Wrapped) // 옵셔널 내외에 값이 있다.
}
// 옵셔널의 타입
let optionalValue : Optional<Int> = nil // 완전한 문법
let optionalValue : Int? = nil // 이렇게도 사용 가능
💡 물음표는 띄어쓰지 않는다!
옵셔널 표현
! (Implicitly Unwrapped Optional)
- 암시적 추출 옵셔널
기존 변수처럼 사용 가능
var optionalValue : Int! = 100
switch optionalValue {
case .none :
print("This Optional variable is nil")
case .some(let value) :
print("Value is \(value)")
}
// ----- 출력값
// Value is 100
// 기존 변수처럼 사용 가능
optionalValue = optionalValue + 1
print(optionalValue!)
// ----- 출력값
// 101
// nil 할당 가능
optionalValue = nil
print(optionalValue)
// ----- 출력값
// nil
// optionalValue에 nil을 할당해놓은 상태에서 + 1을 해주면
// 잘못된 접근으로 인한 런타임 오류 발생
// optionalValue = optionalValue + 1
? (General Optional)
기존 변수처럼 사용 불가- 옵셔널과 일반 값은 다른 타입이므로 연산불가
var optionalValue : Int? = 100
switch optionalValue {
case .none :
print("This Optional variable is nil")
case .some(let value) :
print("Value is \(value)")
}
// ----- 출력값
// Value is 100
// nil 할당 가능
optionalValue = nil
print(optionalValue)
// ----- 출력값
// nil
// 기존 변수처럼 사용불가 - 옵셔널과 일반 값은 다른 타입이므로 연산불가
// optionalValue = optionalValue + 1
옵셔널 추출
- 옵셔널에 들어있는 값을 사용하기 위해 꺼내오는 것이다.
옵셔널 바인딩
- nil 체크 + 안전한 추출
- 옵셔널 안에 값이 있는지 확인하고, 값이 있으면 값을 꺼내온다.
if-let방식을 사용한다.
func printName(_ name : String) {
print(name)
}
var myName : String? = nil
// printName은 기본 타입 그리고 myName은 옵셔널 타입으로
// 전달되는 값의 타입이 다르기 때문에 컴파일 오류발생
// printName(myName)
if let name : String = myName {
printName(name)
}else {
print("myName == nil")
}
// ----- 출력값
// myName == nil
// name 상수는 if-let 구문 내에서만 사용가능하다.
// 상수 사용범위를 벗어났기 때문에 컴파일 오류 발생
// printName(name)
var yourName : String! = nil
if let name : String = yourName {
print(name)
}else {
print("yourName == nil")
}
// ----- 출력값
// yourName == nil
// 쉼표(,)를 사용하여 한 번에 여러 옵셔널을 바인딩 할 수 있다.
// 모든 옵셔널에 값이 있을 때만 동작한다.
myName = "sujeong"
yourName = nil
// yourName이 nil이기 때문에 실행되지 않는다.
// if let name = myName, let friend = yourName {
// print("\(name) and \(friend)")
// }
yourName = "wonseok"
if let name = myName, let boyFriend = yourName {
print("\(name) and \(boyFriend)")
}
// ----- 출력값
// sujeong and wonseok
강제추출
- 옵셔널에 값이 들어있는지 아닌지 확인하지 않고,
강제로 값을 꺼내는 방식이다. - 만약 값이 없을경우(nil) 런타임 오류가 발생하기 때문에 추천하지 않는다.
func printName(_ name: String) {
print(name)
}
// 옵셔널의 값을 강제로 꺼내와서 전달하고자 한다면,
// myName의 옵셔널 물음표가 벗겨지면서 안에 있던 값 sujeong이 강제로 추출되어 (myName!)에 들어온다.
// 그러므로 옵셔널 타입이 아닌 스트링 타입 printName으로 값을 넘겨줄 수 있는 것이다.
var myName : String? = "sujeong"
var yourName : String! = nil
printName(myName!)
// ----- 출력값
// sujeong
myName = nil
// 강제추출시 값이 없으므로 런타임 오류 발생
// print(myName!)
yourName = nil
// nil 값이 전달되기 때문에 런타임 오류 발생
// printName(yourName)
옵셔널 체이닝
옵셔널의 내부의 내부의 내부로 옵셔널이 연결되어 있을 때유용하게 활용할 수 있다.- 매번 nil 확인을 하지 않고
최종적으로원하는 값이 있는지 없는지확인할 수 있다.
예제
// 사람 클래스
class Person {
var name : String
var job : String?
var home : Apartment?
init(name : String) {
self.name = name
}
}
// 사람이 사는 집 클래스
class Apartment {
var buildingNumber : String
var roomNumber : String
var `guard` : Person?
var owner : Person?
init(dong : String, ho : String) {
buildingNumber = dong
roomNumber = ho
}
}
// 옵셔널 체이닝 사용
let sujeong : Person? = Person(name:"sujeong")
let apart : Apartment? = Apartment(dong:"307",ho:"1203")
let superman : Person? = Person(name:"superman")
// 옵셔널 체이닝 실행 후 결과값이 nil일 수 있으므로
// 결과 타입도 옵셔널이다.
만약 우리집 경비원 직업이 궁금하다면?
// 옵셔널 체이닝을 사용하지 않는 경우
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: sujeong)
// 옵셔널 체이닝을 사용하는 경우
func guardJobWithOptionalChaining(owner: Person?) {
if let guardJob = owner?.home?.guard?.job {
print("우리집 경비원의 직업은 \(guardJob)입니다.")
} else {
print("우리집 경비원은 직업이 없어요.")
}
}
guardJobWithOptionalChaining(owner: sujeong)
// ----- 출력값
// 우리집 경비원은 직업이 없어요.
nil 병합 연산자
??- 중위 연산자
- Optional ?? Value
- 옵셔널 값이
nil일 경우,우측 값을 반환한다. - 띄어쓰기에 주의
var guardJob : String
guardJob = sujeong?.home?.guard?.job ?? "슈퍼맨"
print(guardJob)
// ----- 출력값
// 경비원
sujeong?.home?.guard?.job = nil
guardJob = sujeong?.home?.guard?.job ?? "슈퍼맨"
print(guardJob)
// ----- 출력값
// 슈퍼맨
정리
- 옵셔널은
값이 있을수도, 없을수도 있음을 표현한다. - 옵셔널이 아닌 상수에 nil값을 할당하려고 하면 컴파일 오류가 발생한다.
- 옵셔널은
열거형(enum)과 general의 합작품이라고 볼 수 있다. !(Implicitly Unwrapped Optional)은기존 변수처럼 사용이 가능하다.?(General Optional)은 옵셔널과 일반 값은 다른 타입이므로기존 변수처럼 사용이 불가하다.옵셔널 바인딩은 옵셔널 안에 값이 있는지 확인하고, 값이 있으면 값을 꺼내오며if-let 방식을 사용한다.- 옵셔널 바인딩 시 선언한 상수는 if-let 구문 내에서만 사용할 수 있으며, 상수의 사용 범위를 벗어나면 컴파일 오류가 발생한다.
쉽표(,)를 통해한번에 여러 옵셔널을 바인딩할 수 있는데, 모든 옵셔널에 값이 있어야만 동작한다.- 강제추출은 옵셔널에 값이 들어있는지 아닌지 확인하지 않고,
강제로 값을 꺼내는방식이다. - 강제추출은 옵셔널로 선언되어 있는 값을 강제로 추출한 후
옵셔널 타입이 아닌 다른 타입으로 값을 넘겨줄 수 있다. - 옵셔널 체이닝은 옵셔널의 내부의 내부의 내부로 옵셔널이 연결되어 있을 때 유용하며, 최종적으로 원하는 값이 있는지 없는지를 확인한다.
- 옵셔널 체이닝 시, if-let 안에 들어있는 값들을 순서대로 확인하고 그 중 하나라도 값이 없다면, 멈춘 후 else문을 출력한다.
- nil 병합 연산자는
??이렇게 표현하며,옵셔널 값이 nil 일 경우 우측 값을 반환한다.
참고
'Swift > 기술 면접' 카테고리의 다른 글
| Instance 메서드와 Type 메서드의 차이점을 설명하시오. (0) | 2022.05.08 |
|---|---|
| 스토리보드를 이용했을 때의 장단점을 설명하시오. (0) | 2022.05.08 |
| Struct가 무엇이고 어떻게 사용하는지 설명하시오. (0) | 2022.05.08 |
| Class와 Struct의 차이점에 대해 설명하시오. (0) | 2022.05.02 |
| MVC 구조에 대해 블록 그림을 그리고, 각 역할과 흐름을 설명하시오. (0) | 2022.05.01 |