struct Contacts {
var email: [String: String]
var address: String?
func printAdress() {
return print(address ?? "no adress")
}
}
struct Person {
var name: String
var contacts: Contacts?
init(name: String, email: String) {
self.name = name
contacts = Contacts(email: ["home": email], address: "Seoul")
}
func getContacts()-> Contacts? {
return contacts
}
}
var p = Person(name: "James", email: "swift@gmail.com")
let a = p.contacts?.address//마지막 값이 옵셔널이라면 ?를 붙일 필요 없다,
var optionalP : Person? = Person(name: "James", email: "swift@gmail.com")
let b = optionalP?.contacts?.address
// optionalP에 값이 저장되어있다면 contacts속성에 접근하고 그렇지 않다면 바로 종료된다.
b // Seoul - optional String
optionalP = nil
let c = optionalP?.contacts?.address
c // nil - optional String
optiona타입이 없기때문에 마지막 표현식에 따라 String 타입이 리턴된다.
중간에 옵셔널 표현식이 있으므로 마지막 표현식에 따라 타입이 정해지는데 optional String으로 리턴된다.
그리고 nil값이 중간에 나온다면 nil을 리턴시키고 바로 식을 종료시킨다. 하지만 리턴되는 타입은 마지막 표현식에 따라 달라진다.
p.getContacts()?.address // 함수에서 옵셔널 값을 리턴할때는 ()뒤에 ?를 작성해야한다.
let f: (()->Contacts?)? = p.getContacts
//f()?.address // 컴파일 에러 함수 자체가 옵셔널 타입이기 떄문에
f?()?.address // 이런식으로 함수 이름 뒤에도 ?를 붙여야한다.
let d = p.getContacts()?.printAdress()
// 현재 타입은 optional Void 타입으로 Void는 값을 리턴하지 않는다는 키워드 이다.
하지만 nil 값이 아니므로 adress가 출력된다.
if p.getContacts()?.printAdress() != nil { // 호출되었는지 확인하기
}
if let _ = p.getContacts()?.printAdress() {
//값이 호출된 경우에만 바인딩이 성공하지만 보이드 타입이기 때문에
값이 리턴될 필요가 없기 때문에 와일드 카드 패턴을 사용한다.
}
let e = p.contacts?.email["home"]
// 만약 email dictionary가 옵셔널이라면 email?["home"]이렇게 작성되어야한다.
p.contacts?.email["home"]?.count
// 이럴떄는 key와 연관된 값이 없을수 있기때문에 []뒤에 ?을 붙인다.
p.contacts?.address = "Deagu"
// 새로운값 저장 여기서는 모든 표현식이 nil이 아니기 때문에 "Deagu"가 변경된다
optionalP?.contacts?.address = "Deagu"
// optionalP가 nil이기때문에 식이 첫번째 이후로 종료되어 아무런 변화없가 없다.