값이 있을 수도 있고, 없을 수도 있는(nil)
타입을 나타내기 위해 사용type?
과 같이 선언var age: Int? = nil // 옵셔널 Int
var height: Int? = 200 // 옵셔널 Int
옵셔널은 값이 있을수도, 없을수도 있으므로 추출을 통해 값이 실제로 있는지 확인
필요
값이 있으면 변수에 저장
, 없으면 다른 코드 실행if let unwrapped = name { // 값이 있다면 unwrapped에 값이 저장됨
print("\(unwrapped.count) letters")
} else { // 값이 없다면
print("Missing name.")
}
옵셔널에 값이 없으면
추출을 시도한 함수 / 반복문 / 조건문을 바로 탈출
하게 함if-let 구문
과 달리 guard-let 구문
은 구문 이후에도 추출된 옵셔널
사용 가능func greet(_ name: String?) {
guard let unwrapped = name else {
print("You didn't provide a name!")
return
}
print("Hello, \(unwrapped)!") // 추출된 옵셔널 사용 가능
}
greet(nil) // You didn't provide a name
greet("sun") // Hello, sun!
비-옵셔널 타입으로 변환
할 수 있음!
를 붙여서 사용 let str = "5"
let num = Int(str)
print(num) // Optional(5)
let num2 = Int(str)! // 강제 추출
print(num2) // 5
추출 과정이 불필요
값이 없는
경우 런타임 에러
발생!
를 붙여서 선언let str1 = "5"
let str2 = nil
let age = Int(str1)! // 5
let age2 = Int(str2)! // KO : Error
??
은 옵셔널을 추출해서 값이 있으면 해당 값을 반환
하고 값이 없으면 디폴트 값을 반환
func username(for id: Int) -> String? {
if id == 1 {
return "Taylor Swift"
} else {
return nil
}
}
let user = username(for: 15) ?? "Anonymous" // Anonymous
let scores = ["Sun": 100, "Moon": 80, "Star": 120]
let cookieRunScore = scores["Planet"] ?? 0 // nil coalescing
let cookieKingdomScore = scores["Planet", default: 0]
옵셔널이 중첩되어 존재
할 때, 각각을 확인하여 하나라도 nil
인 순간 그 이후는 무시되고, 전체가 nil
이 됨let names = ["Vincent": "van Gogh", "Pablo": "Picasso", "Claude": "Monet"]
let surnameLetter = names["Vincent"]?.first?.uppercased()
throwing function
을 옵셔널을 반환
하는 함수로 변환nil
이 반환되고, 정상 작동하면 옵셔널 반환
enum PasswordError: Error {
case obvious
}
func checkPassword(_ password: String) throws -> Bool {
if password == "password" {
throw PasswordError.obvious
}
return true
}
if let result = try? checkPassword("password") { // 정상 작동
print("Result was \(result)")
} else { // 에러 발생
print("Too EZ")
}
enum PasswordError: Error {
case obvious
}
func checkPassword(_ password: String) throws -> Bool {
if password == "password" {
throw PasswordError.obvious
}
return true
}
try! checkPassword("sekrit")
print("OK")
failable initializer
라고 함init?()
을 통해 선언nil
을 리턴하도록 해야 함struct Person {
var id: String
init?(id: String) {
if id.count == 9 {
self.id = id
} else { // 초기화 실패 시
return nil
}
}
}
var man1 = Person(id: "123456789")
man1?.id // 123456789
var man2 = Person(id: "") // nil
man2?.id // nil
as?
키워드를 통해 클래스의 인스턴스를 부모 혹은 자식 클래스의 타입으로 사용할 수 있는 지 확인 가능해당 타입
(으로 변환 해) 리턴하고 없다면 nil
리턴class Animal {}
class Fish: Animal {}
class Dog: Animal {
func makeNoise() {
print("Woof!)
}
}
let pets = [Fish(), Dog(), Fish(), Dog()]
// Fish 클래스와 Dog 클래스 모두 Animal 클래스를 상속하므로 Swift는 pets가 Animal 배열 타입이라고 추론
// 따라서 Animal 클래스의 프로퍼티/메서드에만 접근 가능하므로 Dog 클래스의 makeNoise()를 호출하려면 타입캐스팅 필요
for pet in pets {
if let dog = pet as? Dog { // 타입 캐스팅
dog.makeNoise()
}
}
nil
을 처리하기 위한 방법이 매우 다양하다는 생각을 했다...어렵다...ㅋㅎㅋㅎㅋㅎ