一个下午让你掌握Swift基础 ( 9/9 ) 可选值

简介

这是一个Swift语言教程,基于最新的iOS 9,Xcode 7.3和Swift 2.2,会为你介绍Swift编程非常基础的内容。从电脑如何工作的全程基本原理到语言结构,你会足够了解这门语言,来处理数据和管理代码的行为。

快速链接

一个下午让你掌握Swift基础 ( 1/9 ) 编程本质 & Playground基础

一个下午让你掌握Swift基础 ( 2/9 ) 变量 & 常量

一个下午让你掌握Swift基础 ( 3/9 ) 数字类型 & 操作

一个下午让你掌握Swift基础 ( 4/9 ) 字符串

一个下午让你掌握Swift基础 ( 5/9 ) 做判断

一个下午让你掌握Swift基础 ( 6/9 ) 重复步骤

一个下午让你掌握Swift基础 ( 7/9 ) 函数

一个下午让你掌握Swift基础 ( 8/9 ) 闭包

一个下午让你掌握Swift基础 ( 9/9 ) 可选值

Swift 初学者 ( 10/12 ) 数组

Swift 初学者 ( 11/12 ) 字典

Swift 初学者 ( 12/12 ) 集合

可选值

你目前遇到的所有变量和常量都有实际的值。当你有一个字符串变量的时候,比如 var name,它有一个相关的字符串值,例如“张嘉夫”。它可能是一个空字符串,像 “”,但尽管如此,还是有一个可以访问到的值。

那是 Swift 自带的安全特色之一:如果说类型是 Int 或 String 那么就有一个实际的整数或字符串在那里,有保证的。

这篇文章会为你介绍可选值(optionals)的概念,一个特殊的 Swift 类型,不只可以表示一个值,也可以没有值。在这篇文章的最后,你会知道为什么需要可选值,以及如何安全的使用它们。

介绍 nil

有时候,有一个没有值的值是很有用的。想象一个场景,你需要访问一个人的认证信息。你想要存储这个人的名字、年龄和职业。名字和年龄都是必须有值的东西—每个人都有。但不是每个人都有工作,所以职业这个值的缺失就是你需要处理的事情。

让我们实际看看这个情况。

在不知道可选值的情况下,这是你可能去表示一个人的名字、年龄和职业的方式:

varname:String="张嘉夫"varage: Int =23varoccupation:String="软件开发者 & 作家"

但如果我被解雇了呢?也许我中了彩票然后再也不想工作了(我真的想!)。这时候能够访问一个不存在的值就会很有用了。

为什么你不能就用一个空的字符串呢?好吧,你可以!让我们讨论一下那样会怎么做,以及为什么可选值是一个更好的选项。

标记值

一个有效值,用来表示不存在的,叫做标记值(sentinel value)。这是前一个例子里你的空字符串就会是这样。

让我们看一下另一个例子。假设你写了一些代码,从服务器上请求什么东西,那么你可以用一个变量来存储服务器返回的任意错误代码:

varerrorCode:Int=0

在成功的时候,你可以用零来表示没有错误。意味着 0 是标记值。

就像职业的空字符串,这可以奏效,但对于程序员有潜在的混淆的风险。0 实际上可能是一个有效的错误代码—也或许在未来会是。无论怎么样,你不能完全确定这是没有错误的。

这两种情况下,如果有一个特殊类型可以表示值的缺失就会更好。这样什么时候有值什么时候没有就很明确了。

Nil表示值的缺失,你会看到 Swift 如何用相当优雅的方式来直接把这个概念并入语言中。

其他有一些编程语言只用标记值。有一些,比如 Objective-C,有 ni 的概念,但仅仅是零的同义词。只是另一个标记值罢了。

Swift 介绍了一个全新的类型,叫做可选值来处理一个值可能是或不是 nil。这意味着如果你在处理一个非可选值类型,那么它就被保证了一定有值,不需要去担心有没有值。总是有的。相似的,如果你在用一个可选值类型,那你就必须要考虑 nil 情况了。它移除了使用标记值带来的歧义。

介绍可选值

可选值是 Swift 对于同时表示值和值的缺失问题的解决方案。一个可选值类型可以引用一个值或是 nil。

把可选值想象为一个盒子:它要么包含一个值,要么没有。当它没有包含值的时候,它被认为包含了 nil。盒子本身总是存在;它一直在这里,你可以打开然后看看里面。

另一方面,字符串或整数,周围并没有这个盒子。相关那里总有一个值,比如 “hello” 或 42。记住,非可选值类型确保有一个实际值。

**注意:**学过物理的这时候可能会想起薛定谔的猫。可选值和它有一点像,除了这不是一个生死攸关的问题!

用下面的语法声明可选值类型:

varerrorCode:Int?

它和标准声明之间的唯一区别就是类型末尾的问号。这个例子里,errorCode 是“ Int 可选值”。这意味着变量本身就像一个盒子,包含一个 Int 或 nil。

设置值很简单。你可以设置它为一个 Int,像这样:

errorCode =100

或者你可以设置它为 ni,像这样:

errorCode =nil

图表可以帮助你形象化理解正在发生什么:

可选值盒子永远存在。当你给变量赋值 100 的时候,你在用值来填满盒子。当你给变量赋值 nil 的时候,你在清空盒子。

花几分钟想一下这个概念。用盒子的类比会是一个巨大的帮助,在你读完这篇文章剩下的部分的时候,然后开始使用可选值。

迷你练习

创建一个叫做 myFavoriteSong 的 String 可选值。如果你有一首最爱的歌,就把它设置为表示那首歌。如果你有不止一首或者没有最爱的,就设置可选值为 nil。

拆包可选值

有可选值一切都很好,但你应该会好奇怎么看到盒子里面,操作它所包含的值。

让我们看看打印可选值的值得时候会发生什么:

letageInteger: Int? =23print(ageInteger)

如下输出:

Optional(30)

那不是你真正想要的—尽管如果仔细想一想,它还是有意义的。你的代码输出了盒子。结果说:“ ageInteger 是一个可选值,包含值 30”。

要看这个值类型如何区别于非可选值类型,那就让我们看看如果尝试把 ageInteger 当一个正常整数来使用会怎么样:

print(ageInteger+1)

代码触发了一个错误:

error: value of optional type'Int?'notunwrapped; did you mean touse'!'or'?'?(错误:可选值类型'Int?'的值没有被拆包;你是不是想使用'!'或'?'?)

不正确是因为你尝试把一个整数加到一个盒子上—不是盒子里面的值,而是盒子本身。这是没有意义的!

强制拆包

错误信息给了解决方案的指示:它告诉你可选值“没有被拆包”。你需要从盒子里把值拆出来。就像过圣诞节!

来看看怎么做。考虑如下声明:

varauthorName:String? ="张嘉夫"

你可以用两种不同的方法来拆包可选值。第一种叫做强制拆包(force unwrapping),像这样做:

varunwrappedAuthorName = authorName!print("作者是\(unwrappedAuthor)")

变量名后面的感叹号告诉编译器你想看到盒子里面,并且把值拿出来。这是结果:

作者是张嘉夫

很棒!这就是你想要的。

使用词语“强制”和感叹号 ! 应该给你传达了一种危险感觉,这值得注意。你应该尽量少的使用强制拆包。要知道为什么,考虑一下如果可选值不包含值得时候会发生什么:

authorName =nilvarunwrappedAuthorName = authorName!print("作者是\(unwrappedAuthorName)")

这个代码产生了如下运行时错误:

fatal error: unexpectedly foundnilwhileunwrapping an Optional value(致命错误:未料到地,拆包一个可选值的时候发现是nil)

发生了这个错误是因为在你尝试拆包变量的时候它没有包含任何值。糟糕的是你是在运行时得到这个错误,而不是编译时,意味着只有在用非法的输入执行这部分代码的时候才会发生,你才能注意到它。更糟糕的是,如果这个代码在一个 app 内部,运行时错误会导致 app 崩溃!

怎么才能让它安全呢?

要在这里停止运行时错误,你可以包住代码,然后用一个检查来拆包可选值,像这样:

ifauthorName !=nil{varunwrappedAuthorName = authorName!print("作者是\(unwrappedAuthorName)")}else{print("没有作者。")}

if 语句检查可选值是不是包含 nil。如果不是,意味着它包含一个你可以拆包的值。

这个代码现在安全了,但仍不失最佳状态。如果你依赖这个技术,每次你想拆包可选值的时候都要记住检查 nil。这会开始变得单调乏味,有一天你会忘记,然后再次导致运行时错误的可能性。

然后回到绘图板!

If let 绑定

幸运的是,Swift 包含了一个叫做if let 绑定(binding)的特色,让你可以安全的访问可选值里面的值。像这样使用:

ifletunwrappedAuthorName:String= authorName {print("作者是\(unwrappedAuthorName)")}else{print("没有作者。")}

你会立马注意到这次没有感叹号了,并且 unwrappedAuthorName 的类型是一个普通的 String,不是一个可选值 String。

**注意:**一般的不会在 if let 语句指定拆包变量的类型,这里是为了显示清楚。

这个特殊语法摆脱了可选值类型。如果可选值包含值,代码执行 if 语句的 if 那边,自动拆包 unwrappedAuthorName 变量,因为你知道这是安全的,可以这么做。

如果可选值不包含值,代码执行 if 语句的 else 那边。这个例子里,unwrappedAuthorName 甚至都不存在。

你可以看到 if let 绑定与强制拆包相比有多么安全,你应该任何可能的时候选择它。

你甚至可以一次拆包多个值,像这样:

letauthorName:String? ="张嘉夫"letauthorAge:Int? =23ifletname:String= authorName,    age:Int= authorAge {print("作者是\(age)岁的\(name)。")}else{print("没有作者或没有年龄。")}

这段代码拆包了两个值。它只在两个可选值都包含值得时候才会执行 if 部分的语句。

现在你知道如何安全的看进一个可选值里面,并且取出值,如果有的话。

迷你练习

使用之前的 myFavoriteSong 变量,使用 if let 绑定来检查是否包含值。如果是,print 这个值。如果没有,print “我没有一首喜欢的音乐。”

把 myFavoriteSong 设置为当前的相反面;也就是说,如果是 nil,就设置为一个字符串,如果是一个字符串,就设置为 nil。观察你 print 的结果会有什么变化。

Nil 合并

有一个终极和更常用的方式来拆包可选值。当你想要取出可选值里的值,不论值是什么,就用它—如果是 nil,就会使用一个默认值。这叫做nil 合并(coalescing)

这是它工作的方式:

varoptionalInt:Int? =10varresult:Int= optionalInt ??0

nil 合并发生在第二行,带有两个问号(??)。这行表示 result 会等于 optionalInt 里的值,或者如果 optionalInt 包含的是 nil 就等于 0。

所以这个例子里,result 包含具体的 Int 值 10。

上面的代码和下面等同:

varoptionalInt: Int? =10varresult: Intifletunwrapped = optionalInt {    result = unwrapped}else{    result =0}

设置 optionalInt 为 nil,像这样:

optionalInt =nilvarresult:Int= optionalInt ??0

现在你的 result 等于 0。

关键点

Nil表示值的缺失。

非可选值变量和常量一定会有一个非 nil 值。

可选值(Optional)变量和常量就像盒子,可以包含一个值或是空的(nil)。

要处理可选值里的值,首先必须从可选值里拆包。

拆包可选值最安全的方式是使用if let 绑定(binding)nil 合并。避免强制拆包(forced unwrapping),它可能会导致一个运行时错误。

接下来去哪儿?

这就是可选值啦,Swift 的一个核心特色,帮助让语言更安全,使用起来更简单。你会发现代码里会贯穿始终使用使用它们。他们帮你让代码更安全,通过保证明确处理值的缺失情况。在你的 Swift 体验中,你应该会越来越欣赏它。

特别是,你会在 10-12 篇教程中使用它们,并且在那里学习集合(collections)。

挑战

你已经学习了可选值背后的理论,并且在实践中见过他们了。现在轮到你搞一下了!

挑战 A:你就是编译器

下列哪个是有效语句?

varname:String? ="嘉夫"varage:Int=nilletdistance:Float=26.7varmiddleName:String? =nil

挑战 B:分而治之

首先,创建一个函数,返回一个整数可以被另一个整数整数的次数。如果不能整除就返回 nil。命名函数为 divideIfWhole。

然后,写代码尝试拆包函数的可选值结果。应该有两种情况:如果成功,print “Yep, 它整除 (answer) 次”,如果失败,print “除不尽 :[”。

最后,测试你的函数:

10 除以 2。应该 print “Yep,它整除 5 次。”

10 除以 3。应该 print “除不尽 :[”

提示 1:使用如下作为函数构造的开始:

funcdivideIfWhole(value: Int, by divisor: Int)

你需要添加返回类型,这应该是一个可选值!

提示 2:你可以使用模除操作符(%)来决定一个值是否能被另一个除尽;回想一下,这个操作返回两个数字相除的余数。例如,10 % 2 = 0 意味着 10 可以被 0 除尽,没有余数,但是 10 % 3 = 1 意味着 10 被 3 除了三次,有一个余数为 1。

挑战 C:重构与改善

上一个挑战里,你用 if 语句写的代码。在这个挑战里,重构代码,使用 nil 合并。这次,所有情况都让它输出 “它除了 X 次”,但如果不是整除,那 X 就应该是 0。

挑战和迷你练习源代码

https://yunpan.cn/cBDRwNvgpHy4G(提取码:f961)

介绍

欢迎来到Swift世界!Swift是一门苹果在2014年夏天发布的编程语言。从那之后,Swift发布了一个主要的版本跳跃,成为了开始在苹果平台:iOS,OS X,watchOS和tvOS开发的最简单的方式。

谁适合这篇教程

这篇教程适合懂一点编程、并且希望学习Swift的人。也许你已经为网站写过一些JavaScript代码,或者用Python写过一些简短的程序。这篇教程就是为你准备的!你会学习到编程的基本概念,同时也会成为Swift语言小能手。

如果你是赤裸裸的编程新手,这篇教程也是为你准备的!教程里贯穿有简短的锻炼和挑战来给你一些编程练习,同时测试你的知识。

需要准备什么

要看这篇教程,你需要准备如下的东西:

一台运行OS X El Captian(10.11)的Mac,带有最新发布的更新并且安装了安全补丁。这样你才能够安装需要的开发工具:最新版本的Xcode。

Xcode 7.3 或更新的版本。Xcode是用Swift写代码的主要开发工具。最小也需要Xcode 7.3版本,因为那个版本包含Swift 2.2。你可以免费从Mac App Store下载Xcode的最新版本,这里:http://apple.co/1FLn51R。

如果你还没有安装Xcode最新版本,在继续看下面的教程前要确定安装。

如何使用这篇教程

每篇教程都会介绍触手可及的话题理论,伴随大量Swift代码来示范在学习的实际的应用程序。

教程里的所有代码都是平台中立的;这意味着不是为iOS、OS X或任何其它平台而特定。代码在playgrounds里运行,你在本篇中已经学习了。

在剩下的教程里,你可以把代码在自己的playground里输入进去。这样你就可以和代码“玩耍”(play around),做一些改变立即就能看见代码运行的结果。

剩下的教程里会贯穿实际小练习,都是简短的练习,关于触手可及的主题。每篇的末尾也有挑战,会有编程问题也会有长一点的代码练习来测试你的知识。做完就能掌握大部分的Swift基础知识。

教程更新

教程会随Swift语言的更新而更新,会发布在我的简书和知乎专栏上,搜索“张嘉夫”即可关注我。

目录

本教程从一些基础工作开始来让你起步:

第1篇,编程本质 & Playground基础- 这就是,到编程世界的入门介绍!你会从电脑和编程的预览开始,然后剩余时间给Swift playground打个招呼。

第2篇,变量 & 常量- 你会学习到变量和常量,这是用来存储数据的“地方”。你也会学习数据类型以及Swift如何追踪数据类型并在代码中进行传输。

第3篇,数字类型 & 操作- 你会从基础的数字类型比如整形和浮点型数字开始,当然也包括布尔类型。也会看到一些在实际操作,从比较到算数操作如加减。

第4篇,字符串- 用字符串来存储文字-从按钮里的文字到图片的标注到这篇教程全部的文字,存储这所有的一切!你会学习到string和character类型,以及基于这些类型的一些常见操作。

在脑海中有基础数据类型后,就该用那些数据做一些事情了:

第5篇,做判断- 代码不总是直接从头运行到尾。你会学习在代码里如何做判决并且设定情况来运行某段代码。

第6篇,重复步骤- 继续不要让代码直线运行的主题,你会学习到如何使用循环来重复某些步骤。

第7篇,函数- 函数是Swift中用来构建代码的基础建筑。你会学习到如何定义函数来分组代码到可复用单元中。

第8篇,闭包(Closures)- 闭包和函数很接近。你会学习到如何使用它们来轻松传递代码块。

最后一篇会回到数据:

第9节,可选值- 这篇讲可选值,Swift中的一种特殊类型,表示既有可能是一个真实的值也有可能没有值。这篇的最后你会知道为什么要用可选值以及如何安全地使用它们。

这些基础会让你快速开始Swift之路,做好接触更高级编程主题的准备。

文/张嘉夫(简书作者)

原文链接:http://www.jianshu.com/p/684413b2cfbb#

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

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

推荐阅读更多精彩内容