美文网首页
一个下午让你掌握Swift基础 ( 9/9 ) 可选值

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

作者: 春泥Fu | 来源:发表于2016-08-25 08:31 被阅读122次

    简介

    这是一个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#

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

    相关文章

      网友评论

          本文标题:一个下午让你掌握Swift基础 ( 9/9 ) 可选值

          本文链接:https://www.haomeiwen.com/subject/sbgosttx.html