强制斯威夫特

问题描述:

通过拆我有以下的执行中,我需要获得访问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是零只是抛出一个错误,但评估正确。

最终的街道参数包含一些“亲爱的车道”,而不是“亲爱的车道”。这是为什么?

发生这种情况的原因是residenceaddress都是可选项,所以有可能可选链评估为零。因此整个表达式被评估为可选的。

为了让你不得不强制解开所有属性的非可选值:

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

但当然,如果有的话在链中的自选的是零,你会得到一个运行时异常

您的代码中的选项存在原因,如果您已经检查了可选项的值,则只需要显式解开变量。如果该值不存在,您的应用程序将崩溃

解开街道名称一次正确的方法是:

john.residence!.address!.streetName 

这解开只有residenceaddress,如果任这些都没有设置,它会引发异常。如果streetName也是可选的,则最后需要添加另一个!

确保您确定您的数据结构。与非期权交易开始是一个很好的做法,如果发生某人不会有residenceaddress,您需要选择权。但是,如果您使用可选项,请确保它们都已被检查!

选项可以使您的代码更安全,更易于阅读,但您必须正确使用它们。

可选链末端的!只打开可选的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