Optional은 2가지 가능성을 표현한다.
사용할 수 있는 값이 존재하거나
존재하지 않거나 (nil
)
?
를 통해 optional type을 생성한다.
// 아직 출판되지 않은 책은 출판년도가 존재하지 않는다.
struct Book {
var name: String // 책 제목
var publicationYear: Int? // 출판년도 (Int optional)
}
let firstDickens = Book(name: "A Christmas Carol", publicationYear: 1843)
// 출판년도: nil
let unannouncedBook = Book(name: “Rebels and Lions”, publicationYear: nil)
// Error
var serverResponseCode = nil
// 404로 설정했지만, 나중에 nil일 수도 있음
var serverResponseCode: Int? = 404
// nil로 설정했지만 나중에 Int값이 올 수 있음
var serverResponseCode: Int? = nil
nil
값이 아님을 확인한 후에 !
를 통해 값을 추출할 수 있다.if publicationYear != nil {
let actualYear = publicationYear!
print(actualYear)
}
nil
값이 아님을 확인하지 않고 nil
값에 !
를 사용하면 런타임 에러가 발생한다.let unwrappedYear = publicationYear! // runtime error
print(unwrappedNumber)
- Safety & Clarity
optional 값에 접근하기 전nil
여부를 확인하는 것은 매우 중요!
// publicationYear 값이 존재할 경우에만 unwrappedPublicationYear에 값을 할당하고 내부 로직 실행
if let unwrappedPublicationYear = book.publicationYear {
print(”The book was published in \(unwrappedPublicationYear)”)
}
else {
print(”The book does not have an official publication date.”)
}
Int
initializer는 Int?
type을 반환한다.// parameter인 String이 Int로 변경될 수 있다면 Int값을 반환
let string = “123”
let possibleNumber = Int(string)
// Int로 변경될 수 없다면 nil을 반환
let string = “Cynthia”
let possibleNumber = Int(string)
// URL값에 해당하는 웹사이트의 텍스트를 반환하는 함수
// URL값에 해당하는 웹사이트가 존재하지 않거나, 해당 사이트에 아무 텍스트가 존재하지 않을 수 있기 때문에 optional 반환
func textFromURL(url: URL) -> String?
// middle name이 존재하지 않는 사람도 있으므로 middleName에 nil값이 올 수 있음
func printFullName(firstName: String, middleName: String?, lastName: String)
struct Toddler {
var name: String
var monthsOld: Int
// Failable Initializer
// Toddler? type의 instance 반환
init?(name: String, monthsOld: Int) {
// nil: 12개월보다 작거나 36개월보다 큰 경우
if monthsOld < 12 || monthsOld > 36 {
return nil
} else {
self.name = name
self.monthsOld = monthsOld
}
}
}
let toddler = Toddler(name: “Joanna”, monthsOld: 14)
if let myToddler = toddler {
print(”\(myToddler.name) is \(myToddler.monthsOld) months old”)
} else {
print(”The age you specified for the toddler is not between 1
and 3 yrs of age”)
}
struct Person {
var age: Int
var residence: Residence? // 주거지가 없는 사람도 존재
}
struct Residence {
var address: Address? // 거주지를 주소로 표현할 수 없을 수 있다.
}
struct Address {
var buildingNumber: String
var streetName: String
var apartmentNumber: String? // 모든 주소가 아파트번호를 가지고 있지는 않는다.
}
?
을 통해 선택적으로 값을 추출할 수 있다.
nil
값이 존재하면 constant에 아무 값도 할당되지 않은 채 if let
문을 빠져나온다.
// 거주지가 존재하고, 주소로 표시가 가능하고, 아파트번호가 있는 경우에만 내부로직 수행
if let theApartmentNumber =
person.residence?.address?.apartmentNumber {
print(”He/she lives in apartment number \(theApartmentNumber).”)
}
모든 non-optional property가 주어져야만 instance가 초기화될 수 있지만, 몇몇 property는 initialize 후에 잠시 nil
값일 수 있다.
implicitly unwrapped optional은 값을 추출하기 위해 if let
을 사용하지 않아도 된다.
하지만, implicitly unwrapped optional의 값이 nil
이면 프로그램이 충돌한다.
-> 꼭 필요한 부분에만 사용해야한다.
class ViewController: UIViewController {
@IBOutlet var label: UILabel!
}
ViewController
가 초기화 된 후, 잠시후에 storyboard에 대응하는 outlet들이 연결된다.
label
은 잠시동안 nil
값을 갖는다.
그 후에 label
은 storyboard와 항상 연결되어 있는데, UILabel?
로 표기한다면 매번 if-let을 써야하므로 비효율적
?
대신 !
(implicitly unwrapped optional)을 써서 해당 값을 사용할 때 자동으로 optional값에서 추출하여 넘겨준다.