var name: String // 컴파일에러
var name = nil // 컴파일에러
만약 Optional(?) 키워드를 사용하지 않았다면 값을 입력하라는 에러가 발생하고, 그 이후에라도 nil을 넣으려하면 컴파일에러가 발생합니다.
Swift가 기본적으로 non-optional 입니다. nil에 대한 컴파일 에러를 통해 개발자는 nil에 대해 명확한 예외처리가 강제 되며, 런타임에 nil로 인한 문제를 컴파일 단계 에서 예방할 수 있습니다.
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
case none // abscence of value
case some(Wrapped) // presence of a value, stored as `Wrapped`
}
< Objective-C 와 Swift의 Optional>
Objective-C의 경우 유효한 객체 가 없을 때 함수에서 nil 포인터를 반환할 수 있다. -> 참조형식에 대해서만 적용이 가능한 개념.
반면 Swift의 optional은 모든 타입에 적용이 가능해 Objective-C보다 표현성이 더 뛰어나다.
let a: Int? // 자동으로 nil 할당
print(a!) // Fatal error: Unexpectedly found nil while unwrapping an Optional value
var address: String? = "Seoul, Korea"
if let addr = address {
print(addr)
}
// URLSession dataTask를 통해 data, response, error 받아서 data 처리
guard let data = data else {
completion(.failure(.APIInvalidResponse))
return
}
프로젝트 구조/프로그램의 로직 상 optional이 무조건 값이 있다면 optional binding을 통해 추출하는 방식이 번거로울 것이다.
이 때 optional로 만들고자 하는 변수나 상수의 타입 뒤에 ? 대신 !를 붙여 implicitly unwrapped optionals를 사용하면 된다.
암시적 추출 옵셔널을 주로 볼 수 있는 경우는 바로 참조 순환을 피하기 위한 class를 초기화할 때 이다.
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}
class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
Optional chaining은 현재 nil일 수도 있는 properties, methods 와 subscripts를 호출하거나 값을 가져올 때 사용하는 방법으로 optional을 반복적으로 사용하여 중첩시킨다. Optional chaining을 통한 접근 역시 optional을 반환하므로 추출 방식 중 하나를 선택해서 진행해야한다.
let person: Person = Person(name: "Sueaty")
if let roomNumber: Int = person.address?.room?.number {
print("Sueaty stays in room: #\(roomNumber)")
} else {
print("Cannot find room number")
}