按照本教程,我正在学习Swift for iOS 8/OSX 10.10 ,并且多次使用术语" unwrapped value ",如本段(在Objects和Class下):
使用可选值时,您可以写吗?在诸如方法,属性和下标之类的操作之前.如果之前的值?是零,一切都在?被忽略,整个表达式的值为零.否则,可选值是解包,并且后面的一切都是?作用于未包装的价值.在这两种情况下,整个表达式的值都是可选值.
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
Run Code Online (Sandbox Code Playgroud)
我没有得到它,并在没有运气的情况下在网上搜索.
这意味着什么?
根据Cezary的回答,原始代码的输出与最终解决方案(在操场上测试)之间存在细微差别:


在第二种情况下,超类的属性显示在输出中,而在第一种情况下有一个空对象.
在这两种情况下,结果不应该是相同的吗?
相关问答:Swift中的可选值是什么?
Cez*_*cik 289
首先,您必须了解可选类型是什么.可选类型基本上意味着变量可以 nil.
例:
var canBeNil : Int? = 4
canBeNil = nil
Run Code Online (Sandbox Code Playgroud)
问号表明事实canBeNil可以nil.
这不起作用:
var cantBeNil : Int = 4
cantBeNil = nil // can't do this
Run Code Online (Sandbox Code Playgroud)
要从变量中获取值,如果它是可选的,则必须将其解包.这只是意味着在最后加上感叹号.
var canBeNil : Int? = 4
println(canBeNil!)
Run Code Online (Sandbox Code Playgroud)
您的代码应如下所示:
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare!.sideLength
Run Code Online (Sandbox Code Playgroud)
旁注:
您还可以使用感叹号而不是问号声明选项以自动解包.
例:
var canBeNil : Int! = 4
print(canBeNil) // no unwrapping needed
Run Code Online (Sandbox Code Playgroud)
因此,修复代码的另一种方法是:
let optionalSquare: Square! = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare.sideLength
Run Code Online (Sandbox Code Playgroud)
您所看到的差异正是可选值被包装的事实的症状.它上面还有另一层.在展开的版本只是表明直对象,因为它是很好,解开.
快速游乐场比较:

在第一种情况和第二种情况下,对象不会自动展开,因此您会看到两个"图层"({{...}}),而在第三种情况下,您只看到一个图层({...}),因为该对象正在自动展开.
第一种情况和后两种情况之间的区别在于,如果optionalSquare设置为后两种情况将给出运行时错误nil.使用第一种情况中的语法,您可以执行以下操作:
if let sideLength = optionalSquare?.sideLength {
println("sideLength is not nil")
} else {
println("sidelength is nil")
}
Run Code Online (Sandbox Code Playgroud)
Com*_*ast 17
现有的正确答案很棒,但我发现,要让我完全理解这一点,我需要一个很好的类比,因为这是一个非常抽象和奇怪的概念.
所以,除了正确的答案之外,让我通过提供不同的视角来帮助那些"右脑"(视觉思维)开发人员.这是一个很好的比喻,对我帮助很大.
生日礼物包装类比
将可选项视为像生日礼物一样,采用坚硬,坚硬,彩色的包装.
在打开礼物之前,你不知道包装内是否有任何东西 - 也许内部什么也没有!如果里面有东西,它可能是另一个存在,它也被包裹,也可能不包含任何东西.你甚至可能打开100个嵌套的礼物,最后发现除了包装之外什么都没有.
如果可选的值不是nil,现在您已显示包含某些内容的框.但是,特别是如果值没有明确地键入并且是变量而不是预定义的常量,那么您可能仍然需要打开框,然后才能知道关于框中的内容的任何具体内容,例如它是什么类型,或者是什么实际价值是.
盒子里装了什么?!比喻
即使在你打开变量之后,你仍然喜欢布拉德皮特在SE7EN的最后一幕(警告:破坏者和非常R级的粗言秽语和暴力),因为即使你打开现在,你仍处于以下情况:你现在有nil,还是一个装有东西的盒子(但你不知道是什么).
你可能知道某事的类型.例如,如果您将变量声明为类型,[Int:Any?]那么您就知道您有一个带有整数下标的(可能是空的)Dictionary,它会生成任何旧类型的包装内容.
这就是为什么在Swift中处理集合类型(字典和数组)可能会变得多毛.
例证:
typealias presentType = [Int:Any?]
func wrap(i:Int, gift:Any?) -> presentType? {
if(i != 0) {
let box : presentType = [i:wrap(i-1,gift:gift)]
return box
}
else {
let box = [i:gift]
return box
}
}
func getGift() -> String? {
return "foobar"
}
let f00 = wrap(10,gift:getGift())
//Now we have to unwrap f00, unwrap its entry, then force cast it into the type we hope it is, and then repeat this in nested fashion until we get to the final value.
var b4r = (((((((((((f00![10]! as! [Int:Any?])[9]! as! [Int:Any?])[8]! as! [Int:Any?])[7]! as! [Int:Any?])[6]! as! [Int:Any?])[5]! as! [Int:Any?])[4]! as! [Int:Any?])[3]! as! [Int:Any?])[2]! as! [Int:Any?])[1]! as! [Int:Any?])[0])
//Now we have to DOUBLE UNWRAP the final value (because, remember, getGift returns an optional) AND force cast it to the type we hope it is
let asdf : String = b4r!! as! String
print(asdf)
Run Code Online (Sandbox Code Playgroud)
Bra*_*n A 13
斯威夫特非常重视类型安全.整个Swift语言在设计时考虑了安全性.这是斯威夫特的标志之一,你应该张开双臂欢迎.它将有助于开发干净,可读的代码,并帮助防止应用程序崩溃.
Swift中的所有选项都用?符号划分.通过将?您声明为可选类型的名称设置为可选项,您实际上将其转换为不在其中的类型?,而是作为可选类型.
注意:变量或类型
Int是不一样的Int?.它们是两种不能相互操作的不同类型.
使用可选
var myString: String?
myString = "foobar"
Run Code Online (Sandbox Code Playgroud)
但这并不意味着你是一个类型的工作String.这意味着您正在使用一种类型String?(String Optional或Optional String).事实上,每当你尝试
print(myString)
Run Code Online (Sandbox Code Playgroud)
在运行时,调试控制台将打印Optional("foobar")." Optional()"部分表示该变量在运行时可能有或没有值,但恰好当前包含字符串"foobar".Optional()除非您执行所谓的"展开"可选值,否则此" "指示将保持不变.
展开可选意味着您现在将该类型转换为非可选类型.这将生成一个新类型,并将该可选内容中的值分配给新的非可选类型.这样,您就可以对该变量执行操作,因为编译器已经保证它具有可靠的值.
有条件地展开将检查可选中的值是否为nil.如果不是nil,则会有一个新创建的常量变量,该变量将被赋值并展开到非可选常量中.从那里你可以安全地使用if块中的非可选项.
注意:您可以为有条件的展开常量提供与要展开的可选变量相同的名称.
if let myString = myString {
print(myString)
// will print "foobar"
}
Run Code Online (Sandbox Code Playgroud)
有条件地展开选项是访问可选值的最简洁方法,因为如果它包含nil值,那么if let块中的所有内容都不会执行.当然,像任何if语句一样,您可以包含else块
if let myString = myString {
print(myString)
// will print "foobar"
}
else {
print("No value")
}
Run Code Online (Sandbox Code Playgroud)
强制解包是通过使用所谓的!("bang")运算符来完成的.这不太安全,但仍然允许您的代码编译.但是,无论何时使用bang运算符,在强行展开之前,必须确保变量确实包含一个实数值.
var myString: String?
myString = "foobar"
print(myString!)
Run Code Online (Sandbox Code Playgroud)
以上是完全有效的Swift代码.它打印出的值myString被设置为"foobar".用户会foobar在控制台中看到打印出来的内容.但是我们假设从未设置过该值:
var myString: String?
print(myString!)
Run Code Online (Sandbox Code Playgroud)
现在我们手上有不同的情况.与Objective-C不同,只要尝试强制解包可选项,并且尚未设置可选项,并且nil当您尝试打开可选项以查看应用程序中的内容将崩溃时.
打开w/Type Casting.正如我们之前所说的那样,虽然您是unwrapping可选的,但实际上是在转换为非可选类型,您也可以将非可选类型转换为其他类型.例如:
var something: Any?
Run Code Online (Sandbox Code Playgroud)
在我们的代码中的某个地方,变量something将被设置为具有某个值.也许我们正在使用泛型,或者可能还有一些其他逻辑会导致这种情况发生变化.所以稍后在我们的代码中我们想要使用,something但如果它是不同的类型仍然能够区别对待它.在这种情况下,您将需要使用as关键字来确定:
注意:
as运算符是您在Swift中键入强制转换的方式.
// Conditionally
if let thing = something as? Int {
print(thing) // 0
}
// Optionally
let thing = something as? Int
print(thing) // Optional(0)
// Forcibly
let thing = something as! Int
print(thing) // 0, if no exception is raised
Run Code Online (Sandbox Code Playgroud)
注意两个as关键字之间的区别.就像之前我们强行打开一个选项一样,我们使用了!bang操作符来这样做.在这里你将做同样的事情,但不是铸造只是一个非可选的你也在铸造它Int.它必须能够被贬低Int,否则就像使用bang操作符一样,当nil你的应用程序崩溃时.
并且为了在某种或数学操作中使用这些变量,必须将它们解包以便这样做.
例如,在Swift中,只有相同类型的有效数字数据类型可以相互操作.当您使用as!强制转换该变量的类型转换类型时,就像您确定它属于该类型一样,因此可以安全地操作并且不会使应用程序崩溃.只要变量确实属于你所使用的类型,这是可以的,否则你手上就会弄得一团糟.
尽管如此,使用as!将允许您的代码进行编译.通过铸造as?是一个不同的故事.实际上,as?将您声明Int为完全不同的数据类型.
现在它是 Optional(0)
如果你曾经尝试过做类似的功课
1 + Optional(1) = 2
Run Code Online (Sandbox Code Playgroud)
你的数学老师可能会给你一个"F".与Swift相同.除了Swift之外根本不会编译而不是给你一个分数.因为在一天结束时,可选实际上可能是零.
安全第一孩子.