关闭

如何理解Swift中Optional的 ! 和 ?

标签: swiftoptionalios
1583人阅读 评论(4) 收藏 举报

很多人在刚上手swift时对于Optional中 ‘!’ 和 ‘?’ 的使用十分不理解,接下来我会谈一谈自己对于这两个符号的使用方式的理解。

先来说说Optional的概念,以方便之后的理解。来看一下下面的代码:

var a : String = nil              // 编译错误,String类型不能为nil
var b : String = “Hello!”

Swift 中的普通类型不再能设为nil。那如何表示这个值不存在呢?所以引进了Optional的概念:代表 nil 或某个具体的值。例如:

var c : String? = nil       
var d : String? = “Hello!” 

String? 就是一个Optional,它既能够被具体类型赋值, 也可以赋值为nil。通过 String 和 Optional的比较,发现Optional 就相当于把具体类型和 nil 打包捆绑在了一起,转变成了一种新的类型。

Optional 有两种声明方法:

var apple: String?   
var bread: String!   

很多人认为,声明为 String! 的变量表明该变量的值不为 nil。但是,实际上,String! 和 String? 都是有默认值的,且默认值都为nil。我们为它们赋一个初值再打印类型来看看:

var apple: String? = “apple”   
var bread: String! = “bread”
(lldb) p apple
(String?) $R0 = “apple”

(lldb) p bread
(String?) $R1 = “bread”

发现,尽管apple 和 bread 虽然一个是 String? 一个是 String! 但是打印出来都是 String? 类型的。所以更恰当的理解应该是:String! 只是理解意义上的不为nil,其本质还是一个 Optional,从声明来说它和 String? 完全等价,所以也能够赋值为 nil 。

为了之后叙述方便,我们把定义类似 String? 的称为 Optional(?), 定义类似 String! 的称为 Optional(!)。

Optional 的本质是囊括 nil 和具体类型的一种枚举。获取它具体值的操作过程称之为拆包,用 “!” 表示。先来做个实验:

var string : String
var optionalString: String?   
var nonOptionalString: String!

string = nonOptionalString    // ① 崩溃
string = optionalString      // ② 编译错啦
string = optionalString!     // ③ 崩溃

具体看一下报错原因:
① String! 赋值给 String ,报错为:拆包时Optional的值为nil;
② String? 赋值给 String,编译器报错为 Optional未拆包;
③ 拆包后的 String? 赋值给 String,这时,报错为:拆包时Optional的值为nil;
String! 和 拆包后的 String? 进行传值时报的错相同,由此我们可以得出一个结论:编译器默认 Optional(!) 是确定有值的,所以不需要再对 nil 的情况进行处理。Optional(!) 的变量只是给予了自动拆包的权限,在实际使用它的过程中不需要再次使用 ‘!’ 进行拆包。在swift官方文档中称为:Implicitly Unwrapped Optional (隐式拆包),也可以理解成“拆过包了”。

但是,只有在变量确认有值的情况下才能进行拆包。就像如上代码,optionalString 为nil,进行拆包就会引发崩溃。swift官方建议,Optional 使用 if + ! 结合的方式或者 if let 进行安全地拆包。简单的看下代码:

if optionalString != nil {
   append(string: optionalString!)
} else {
   // do something
}
if let actualString = optionalString {
   append(string: actualString)
} else {
   // do something
}

再次提醒一下,Optional(!) 和 Optional(?) 都可以使用这两种方式进行安全地拆包,只是编译器不会对没有处理 nil 情况的 Optional(!) 报错。

下图展示了 Optional 和 String 可接收类型的比较:

拆完包之后的 Optional 其实就是 String 类型。编译器强制使用者在变量为 nil 的时候要进行处理,否则就会报错会崩溃。String! 是为了规避变量一定不为 nil 的情况下却要反复判断是否为 nil 的冗余代码而产生的。例如,我们在使用 IBOutlet 时,一定会定义成 Optiona(!)。String! 在声明时和 String? 完全等价,在使用时和 String 完全等价。

总结一下:

  1. Optional的本质是一个包含了 nil 和普通类型的枚举,这是为了确保使用者在变量为 nil 的情况下会完成相应的处理;
  2. 无论是 Optional(!) 还是 Optional(?) 都是一种Optional,在未设初始值时,默认为nil。Optional(!) 只是给予了自动拆包的权限,省略了判断其值是否为nil的过程,但是不能够保证它的值不为nil;
  3. Optional(!) 在声明时和 Optional(?) 等价,在使用时和具体类型等价;
  4. 一定要确保 Optional 不为 nil 的情况下才可直接拆包,不然会引发崩溃。
2
0
查看评论

理解Swift中Optional类型-有和无的哲学

原文连接:http://blog.barat.cc/ios/understanding-swift-optional/nil的遗憾当某个变量或表达式没有任何内容时,在Objective-C中可以使用nil来表示。nil在Objective-C中是一个「野孩子」,void指针指向数字 0,本质上来讲n...
  • offbye
  • offbye
  • 2016-01-20 09:39
  • 1552

如何理解Swift中Optional的!和?

很多人在刚上手swift时对于Optional中 ‘!’ 和 ‘?’ 的使用十分不理解,接下来我会谈一谈自己对于这两个符号的使用方式的理解。
  • qq_23292307
  • qq_23292307
  • 2017-09-11 11:03
  • 266

Swift学习之七:Optional value(可选值)

当值可能不存在(may be absent)的时候使用Optionals,
  • woaifen3344
  • woaifen3344
  • 2014-06-08 15:32
  • 14463

Swift 关于字符串 Optional("123")输出的问题。

RT
  • onlychengzhi
  • onlychengzhi
  • 2017-03-08 14:16
  • 703

swift optional总结 (二)

有 或 无,这是一个问题。 Swift的伟大设计之一,是非常巧妙的解决了「有」和「无」之间的哲学关系。通过Optional数据类型,可以让一个变量有值,也可以没有值。很多其他的编程语言也提供类似的机制表示一个对象「没有内容」,而Swift中的Optional还可以作用在Int这样的「基本数据类型」...
  • binglan520
  • binglan520
  • 2016-10-10 16:20
  • 529

Swift3.0 Optional String 类型 强制拆包

/**          Swift3.0中 String的 Optional在String作为urlString去初始化url并进行网络访问时,会出现url为Optional包string的错误情况      &#...
  • jeffasd
  • jeffasd
  • 2017-03-15 16:44
  • 2050

swift 中,protocol的optional方法

swift推出一年多了,断断续续学了一些,一直没有真正引入自己的项目中。 最近准备做一个 Today Extension,恰好是一个机会可以完整的使用swift开发。刚刚做了几天,就发现又一次被Apple忽悠了,感觉就像iOS6.0时代的AutoLayout,经常掉坑儿里。 尤其是swif...
  • wershest
  • wershest
  • 2015-08-15 16:15
  • 2907

Swift_协议、代理(protocol、delegate可选@objc optional与必需、协议扩展、is as? as!检查协议)

ProtocolClass2.swift import UIKit //定义协议 protocol ProClassDelegate { //代理函数 func test(name:String,type:Int) func test2() } class Protoc...
  • Jason_chen13
  • Jason_chen13
  • 2017-08-21 16:28
  • 519

随手记Swift基础和Optional Type(问号?和感叹号!)

距离Apple推出Swift已经有几天了,网上也时不时出现“急招Swift程序员,要求有一天工作经验”的帖子。看到Swift,除了苹果放的另外一门语言的链接(http://swift-lang.org/),还可能联想到Taylor Swift,或者铃木雨燕。这几天网上关于Swift的话题和材料应该迅...
  • jasonblog
  • jasonblog
  • 2014-06-06 15:07
  • 34107

理解Swift中的Optional

让我们来看一个例子: class Father{ var child: Child = Child() ... } class Child{ var pet: Pet = Pet() } class Pet{ func jump(){ ...
  • zzdwuliang
  • zzdwuliang
  • 2016-07-15 22:38
  • 241
    个人资料
    • 访问:1594次
    • 积分:31
    • 等级:
    • 排名:千里之外
    • 原创:0篇
    • 转载:0篇
    • 译文:0篇
    • 评论:4条
    文章存档