-
swift - Optional Chainingswift 2021. 1. 4. 20:28
Optional Chaining
struct Contacts { var email: [String: String] var address: String } struct Person { var name: String var contacts: Contacts init(name: String, email: String) { self.name = name contacts = Contacts(email: ["home": email], address: "Seoul") } } // 두가지만 기억하자 // 1. Optional Chanining의 결과는 항상 Optional이다 // 2. Optional Chanining에서 포함된 표현식 중에서 하나라도 nil을 리턴한다면 뒤의 표현식을 평가하지 않고 nil을 리턴한다. var p = Person(name: "James", email: "swift@example.com") let a = p.contacts.address var optionalP: Person? = Person(name: "James", email: "swift@example.com") // optionalP에 nil이 포함되어 있다면 그냥 nil을 리턴 아니면 쭈욱 가고 let b = optionalP?.contacts.address optionalP = nil let c = optionalP?.contacts.address
자 여기서 a, b, c의 데이터 타입이 Optional인지 아닌지 확인해보면
a는 Optional이 아니고 b와 c는 Optional이다.
왜? a는 당연히 Optional Chaining으로 접근한게 아니기 때문에 non-Optional 형태의 자료형이고
b와 c는 Optional Chaining으로 접근했기 때문에
더 자세히 보면 b와 c는 값을 할당하는 표현식에서 Optional 표현식 (optionalP?) 가 있기 때문에!
표현식 중에 하나라도 Optinal 표현식이 포함되어 있다면 최종 데이터 타입은 Optional이 된다.
nil이 리턴된다면 3번째 표현식 까지만 평가한다.
contacts의 자료형을 Optional로 바꾸면
관련된 표현식에 ! 나 ?를 붙여줘야하는데 !는 위험하니까 ?를 붙인다.
struct Contacts { var email: [String: String] var address: String } struct Person { var name: String var contacts: Contacts? init(name: String, email: String) { self.name = name contacts = Contacts(email: ["home": email], address: "Seoul") } } var p = Person(name: "James", email: "swift@example.com") let a = p.contacts?.address var optionalP: Person? = Person(name: "James", email: "swift@example.com") // optionalP에 nil이 포함되어 있다면 그냥 nil을 리턴 아니면 쭈욱 가고 let b = optionalP?.contacts?.address optionalP = nil let c = optionalP?.contacts?.address
다시 데이터형을 보면 표현식에 Optional 다 들어가 있기 때문에 모두 Optional 자료형이 된다.
괄호 전, 후에 ?를 붙이는 경우
struct Person { var name: String var contacts: Contacts? init(name: String, email: String) { self.name = name contacts = Contacts(email: ["home": email], address: "Seoul") } func getContact() -> Contacts? { return contacts } } var p = Person(name: "James", email: "swift@example.com") p.getContact()?.address let f: (() -> Contacts?)? = p.getContact f?()?.address
함수나 메소드가 리턴하는 메소드 값에 접근할 때는 괄호 뒤에 ?를 붙인다 정도만 일단 기억해두자
기타 옵셔널 체이닝 속성
struct Contacts { var email: [String: String]? var address: String func printAddress() { return print(address ?? "no address") } } struct Person { var name: String var contacts: Contacts? init(name: String, email: String) { self.name = name contacts = Contacts(email: ["home": email], address: "Seoul") } func getContact() -> Contacts? { return contacts } } // 두가지만 기억하자 // 1. Optional Chanining의 결과는 항상 Optional이다 // 2. Optional Chanining에서 포함된 표현식 중에서 하나라도 nil을 리턴한다면 뒤의 표현식을 평가하지 않고 nil을 리턴한다. var p = Person(name: "James", email: "swift@example.com") let a = p.contacts?.address var optionalP: Person? = Person(name: "James", email: "swift@example.com") // optionalP에 nil이 포함되어 있다면 그냥 nil을 리턴 아니면 쭈욱 가고 let b = optionalP?.contacts?.address optionalP = nil let c = optionalP?.contacts?.address p.getContact()?.address let f: (() -> Contacts?)? = p.getContact f?()?.address // ()? -> Optional void 값을 리턴하지 않는다는 키워드 let d = p.getContact()?.printAddress() // 이러한 구조를 알면 실제로 메소드가 호출되었는지 확인 가능 if p.getContact()?.printAddress() != nil { // nil이 아니고 ()?가 호출되면 여기가 호출됨 } if let _ = p.getContact()?.printAddress() { // 어차피 성공하면 ()?이 반환되기 때문에 wildcard 로 선언 } let e = p.contacts?.email?["home"] // dictionary가 옵셔널로 선언되어 있으면 [] 앞에 ? 선언 // 서브 스크립트접근할때는 [] 뒤에 ? 선언 p.contacts?.email?["home"]?.count p.contacts?.address = "Daegu" p.contacts?.address optionalP?.contacts?.address = "Daegu" optionalP?.contacts?.address
이정도로 정리하고 나중에 한번 더보자
'swift' 카테고리의 다른 글
swift - Functions (0) 2021.01.04 swift - Optional Pattern (0) 2021.01.04 swift - Nil-Coalescing Operator (0) 2021.01.04 swift - IUO(Implicitly Unwrapping Optionals ) (0) 2021.01.04 swift - Optional Binding (0) 2021.01.04