2014-09-10 77 views
1

通過拆我有以下的執行中,我需要獲得訪問streetName如圖所示:強制斯威夫特

if let street = john.residence?.address?.streetName { 

    street // Darling Lane // This prints string correctly 
} 

let street = john.residence?.address?.streetName! // Some "Darling Lane" The bang sign // at the end does not forcefully unwraps the optional 

有什麼理由?

更新:

好吧,我現在很困惑!這裏是完整的代碼:

class Person { 
    var residence :Residence? = Residence() 
} 

class Residence { 
    var address :Address? = Address() 
} 

class Address { 
    var streetName :String? = "Darling Lane" 
    var zipCode :String? 
    var city :String? 
} 


let street = john.residence?.address?.streetName! 

在上面的代碼中,我說如果居住不是空的,他們前進。當你到達streetName然後給我的價值,我不在乎如果streetName是零隻是拋出一個錯誤,但評估正確。

最終的街道參數包含一些「親愛的車道」,而不是「親愛的車道」。這是爲什麼?

回答

1

發生這種情況的原因是residenceaddress都是可選項,所以有可能可選鏈評估爲零。因此整個表達式被評估爲可選的。

爲了讓你不得不強制解開所有屬性的非可選值:

let street: String = john.residence!.address!.streetName! 

但當然,如果有的話在鏈中的自選的是零,你會得到一個運行時異常

1

您的代碼中的選項存在原因,如果您已經檢查了可選項的值,則只需要顯式解開變量。如果該值不存在,您的應用程序將崩潰

解開街道名稱一次正確的方法是:

john.residence!.address!.streetName 

這解開只有residenceaddress,如果任這些都沒有設置,它會引發異常。如果streetName也是可選的,則最後需要添加另一個!

確保您確定您的數據結構。與非期權交易開始是一個很好的做法,如果發生某人不會有residenceaddress,您需要選擇權。但是,如果您使用可選項,請確保它們都已被檢查!

選項可以使您的代碼更安全,更易於閱讀,但您必須正確使用它們。

2

可選鏈末端的!只打開可選的streetName,而不打開預期的整個可選鏈。如果streetName被聲明爲類型String而不是String?String!您將收到有關嘗試解包非可選值的錯誤。

假如你這樣做,而不是:

let street = (john.residence?.address?.streetName)! 

它會工作。當然,如果residence,addressstreetName中的任何一個爲nil,那麼您將會試圖解開nil。這就是爲什麼你提出的第一種方法是首選。

答到UPDATE

只有一個可選的變量可以是nil。這就是爲什麼可選鏈的結果必須具有可選類型的原因。

street的類型在編譯時建立。編譯器會發現您有一系列可選項,並使得street的類型爲String?。不要緊,你在鏈條的末端解開街道的價值。由於residenceaddress可能是nil,因此可選項鍊可能會返回nil,因此編譯器必須將street的類型設置爲可選項,以便它可以保存nil(如果是結果)。

當你這樣寫:

let street = john.residence?.address?.streetName! 

實際上,這就是你的代碼是這樣做的:

var street: String? 
if john.residence == nil { 
    street = nil 
} else if john.residence!.address == nil { 
    street = nil 
} else { 
    // here we have fully unwrapped the street name 
    // but it is still assigned to street which 
    // is an optional variable 
    street = john.residence!.address!.street! 
} 

唯一的區別是,它是在一個鏡頭,所以你能夠使用let完成而不是var