如何理解Swift中Optional的!和?

很多人在刚上手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<String>的比较,发现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> 和 String 可接收类型的比较:

拆完包之后的 Optional<String> 其实就是 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 的情况下才可直接拆包,不然会引发崩溃。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 很多人在刚上手swift时对于Optional中 ‘!’ 和 ‘?’ 的使用十分不理解,接下来我会谈一谈自己对于这...
    子疯zp阅读 268评论 0 0
  • 对各种值为"空"的情况处理不当,几乎是所有Bug的来源。 在我们的例子里,尽管tmp的值是nil,但调用tmp的r...
    AKyS佐毅阅读 10,496评论 1 13
  • 关于 Swift 重要这个文档所包含的准备信息, 是关于开发的 API 和技术的。这个信息可能会改变, 根据这个文...
    无沣阅读 4,275评论 1 27
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,775评论 1 10
  • 2013 年 8 月 21 日,程浩走了。不知不觉,到今天,程浩已经离开我们三年。这是 14 年程浩生日那天,我写...
    陈章鱼阅读 312评论 1 2