Optional 是 Swift 的一个非常重要的特性,它除了提供类型安全的机制,也是 Swift 中很多语言特性的核心。当然,使用 Optional 时也要了解很多坑,这样能帮助我们更好的运用它。

Optional

Optional 是 Swift 中一种特殊的类型,它本身有一个枚举的定义,简单来说就是这个形式:

enum Optional {
case None
case Some
}

当然,Swift 中这个枚举的实际定义要复杂的多,这里只为了帮助大家最简单的了解。一个 Optional 的值,要么是空(None), 要么就会包含一个值(Some)。

比如我们可以声明一个 Optional 的 String 类型的变量,只需要在变量定义的时候在类型后面加上一个 ?

var name: String?

如果这个变量是标识成 Optional 的,我们在引用它的时候就必须做一些特殊的处理,可以使用强制解包:

print(name!)

在变量后面添加一个 ! ,相当于告诉编译器,我确信这个变量不是 nil,可以直接使用(当然,使用强制解包只代表你自己确认它不为 nil,但它还是有可能为 nil 的,如果这样的情况发生,依然会造成程序运行时崩溃)。

相比使用强制解包,更加安全和优雅的方式是使用 Optional Chaining:

if let nameValue = name {
print(nameValue)
}

使用 if let 这样的语法就可以更加安全的操作 Optional 值。只有在 name 中的值不为 nil 的时候,nameValue 变量才会被初始化成功。 这样我们的 print 语句就不会因为 nil 而崩溃。

虽然我们使用 Objective-C 的时候也可以进行类似这样的判断 if value != nil { ... }, 但 Optional 的好处是,它是编译级别的,只要一个值被标识成 Optional 的,它就必须在引用的时候进项非空判断,无论你使用强制解包还是 Optional Chaining。这样我们代码的类型安全就得到很大的增强。

Optional Chaining 陷阱

相信上面对于 Optional 以及 Optional Chaining 的介绍,大家或多或多少已经了解过了。下面咱们就来说说一些 Optional Chaining 的小细节。

既然叫做 Optional Chaining,顾名思义,它是可以进行链式操作的。也就是说,我们可以连续调用 Optional 相关操作,比如,我们有这样的类结构:

struct Name {

    var firstName: String = ""
var lastName: String = "" } struct Person { var name: Name?
var age: Int }

然后,我们这样进行调用:

var person:Person? = Person(name: Name(firstName: "san", lastName: "Zhang"), age: 18)
print(person?.name?.firstName) // 输出?

这时候 print 语句的输入是什么呢? 如果看 firstName 属性的定义的话:

var firstName: String

是不是会认为会直接输出 san 呢? 但并不是这样,输出的结果会变成这样:

"Optional("san")"

firstName 明明不是 Optional 类型的值,怎么会输出成 Optional 的呢,这时因为 firstName 虽然本身不是 Optional 的,但它却处在 Optional Chaining 中,我们看一下它的整个引用:

person?.name?.firstName

这个引用中,person 和 name 都是 Optional 的。只要一个表达式中有一个 Optional 的值,整个表达式的结果就都是 Optional 的,不论最后一个属性本身是否是 Optional 的。

仔细想想这样是很合理的,比如我们这个表达式中,如果 person 是 nil 呢?那么这个 Optional Chaining 就会提前返回,因为 person 都是 nil 了,后面的属性引用就没有意义了。所以我们就需要对这个表达式进行 Optional 处理。

那么, 正确的引用方式应该是这样:

if let firstName = person?.name?.firstName {

    print(firstName)

}

现在, print 语句的输出就正常了。同样的, Optional Chaning 作为函数返回值也需要注意:

func getName(person: Person) -> String {

    return person.name?.firstName

}

同样的道理,getName 函数返回的是一个 String 类型。 firstName 属性也是 String 类型。但这个函数定义编译不会通过。和我们刚才的将的是同样的道理,因为 return 语句的表达式也是一个 Optional Chaining。所以我们的函数需要定义成这样:

func getName(person: Person) -> String? {

    return person.name?.firstName

}

实际应用

说了这些 Optional 的特性,也举了一些简单的例子。这些特性在我们的日常开发实践中也很常见,比如:

class WebViewDelegate :NSObject, UIWebViewDelegate {

    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if let absURL = request.URL?.absoluteString {

            // do something..

            return false

        }

        return true

    }

}

我这里的 UIWebView 的代理对象,会在每次加载网页的时候对页面的地址进行处理。 首先要取到页面的地址:

if let absURL = request.URL?.absoluteString {

	//...

}

这里的 request.URL?.absoluteString 就是一个 Optional Chaining,所以我们要先将它解包出来,然后再进行处理。

如果我们没注意这个的话,很天真的使用这种形式:

if request.URL?.absoluteString == "xxx" {
}

就会产生编译错误了,还会耗费很多时间去调试~

结语

Optional 是 Swift 最核心的特性之一,使用得当,它能够提高我们开发的效率,以及程序的安全性,好处多多。当然也要深入去了解它的特性,这样我们就能避免它产生的陷阱,从而更加游刃有余的徜徉在 Swift 的海洋中。

Swift - 关于 Optional 的一点唠叨的更多相关文章

  1. Swift的Optional类型

    我们使用Swift这个苹果新推出的编程语言已经有一段时间了.其中的一个极大的优点就是苹果称为“optional types”的东西.几乎所有的objective-c程序员都知道用nil来表示某个引用类 ...

  2. Swift 学习中的一点体会,不断更新中。。。

    随着Xcode 8的发布,swift 3.0终于来了.又有一大批api名字发生了变化.但是感觉3.0之后的变化应该会小些,因此再重新仔细学习一下. 1. 关于swift引入的Computed Prop ...

  3. swift:Optional Type 、Swift和Objective-C混编的讲解

    ❤️❤️❤️swift中的Optional Type的?和!含义:其实就是一个装包和拆包的过程 optional的含义: Optional事实上是一个枚举类型,Optional包含None和Some两 ...

  4. 漫谈 KVC 与 KVO

    KVC 与 KVO 无疑是 Cocoa 提供给我们的一个非常强大的特性,使用熟练可以让我们的代码变得非常简洁并且易读.但 KVC 与 KVO 提供的 API 又是比较复杂的,绝对超出我们不经深究之前所 ...

  5. Swift optional详解

    学习了一阵swift对于optional类型一直不是很了解,为此特意学习了一下,通过观看斯坦福大学的视频,将他所讲的进行了总结 optional 有两个值 1.not set (未设) 代表这个值没有 ...

  6. Swift编程语言简介

    这篇文章简要介绍了苹果于WWDC 2014发布的编程语言Swift.                                                                   ...

  7. 来自苹果的编程语言——Swift简介转载】

    关于 这篇文章简要介绍了苹果于WWDC 2014发布的编程语言——Swift. 原文作者: Lucida Blog 新浪微博 豆瓣 转载前请保留出处链接,谢谢. 前言 在这里我认为有必要提一下Brec ...

  8. 转 苹果的新编程语言 Swift 简介

    苹果官方文档地址 https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Pro ...

  9. 来自苹果的编程语言——Swift简单介绍

    关于 这篇文章简要介绍了苹果于WWDC 2014公布的编程语言--Swift. 原文作者: Lucida Blog 新浪微博 豆瓣 转载前请保留出处链接.谢谢. 前言 在这里我觉得有必要提一下Brec ...

随机推荐

  1. java生成6位随机数

    生成6位随机数(不会是5位或者7位,仅只有6位): System.out.println((int)((Math.random()*9+1)*100000)); 同理,生成5位随机数: System. ...

  2. [TypeScript] Find the repeated item in an array using TypeScript

    Say you have an array that has at least one item repeated. How would you find the repeated item. Thi ...

  3. [Docker] Build Your Own Custom Docker Image

    In this lesson we will cover how to build your own custom Docker image from scratch. We'll walk thro ...

  4. ZOJ 3209 Treasure Map DLX

    用最少的矩阵覆盖n*m的地图.注意矩阵不能互相覆盖. 这里显然是一个精确覆盖,但因为矩阵拼接过程中,有公共的边,这里须要的技巧就是把矩阵的左边和以下截去一个单位. #include <stdio ...

  5. url前面双斜杠、单斜杠、无斜杠、点+单斜杠的总结

    原文:url前面双斜杠.单斜杠.无斜杠.点+单斜杠的总结 本来只是一个绝对url和相对url的简单问题,但实际使用中会碰到一些不常见的,比如双斜杠,经常不用竟然忘了,做一下总结.可以参考一下这篇文章 ...

  6. 如何快糙好猛的使用libfacedetection库【最新版】

    前言 最近已经很少看CSDN了.这一年多准备考研,基本上怕是不会再怎么上了.以前有一个http://blog.csdn.net/mr_curry/article/details/51804072 如何 ...

  7. 【14.67%】【codeforces 615D】Multipliers

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  8. linux 分发同步脚本与分发命令脚本

    同步脚本,在第5步要拼接自己配置的主机名 #!/bin/bash # 获取输入参数个数,如果没有参数,直接退出 pcount=$# )); then echo no args; exit; fi # ...

  9. 【16.67%】【codeforces 667C】Reberland Linguistics

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  10. 前端构建工具里babel-polyfill的使用问题

    看了很多react工程的package.json文件,里面都没有使用babel-polyfill,那对ES6的新API是如何做到被IE9这样的浏览器识别的呢,难道在webpack打包的时候通过别的方式 ...