Swift Optionals: When to use if let, when ? and !, when as? and as

翻译 2015年07月08日 16:38:42

原文地址:http://www.touch-code-magazine.com/swift-optionals-use-let/

1. 可选类型是什么?

回忆你知道的普通的数据类型,就像你在的Objective-C(或PHP,JavaScript等)等代码中曾经看到的。比方说,你有两个变量叫“age”和”height”。他们是简单的Int类型的,可以容纳任何整数。让我们来看一个简单的代码示例:

var age: Int = 35
let height: Int = 180

通过使用关键字“var”声明变量“age”并且赋值为35。你可能会改变你的想法后来并指定另一个值,例如36,你可以改变很多次。相反的,“height”是一个常数 —一旦你赋值100,那它的值永远不变!

在这两种情况下,你都知道Int包含一个整数值。你不能做的是给变量age赋值为空值(nil)。

例如,如果这些数据块代表员工的资料在公司数据库,对一些记录,你可能不知道员工的身高(height) — 在这种情况下,你不应该将它设置值为0,你应该将这个值设置为空或缺失。

遇到上面的情况你应该使用可选的数据类型。

很多人不知道,可选(Optional)实际上是在Swift的标准库中定义,并加入一些语法糖的枚举类型。它看起来像这样(简略的):

enum Optional : NilLiteralConvertible {
  case None
  case Some(T)
}

因此,可选(Optional)可以包含空 - 既然是遵循NilLiteralConvertible协议,可以猜测,那就是当你要使用nil时可以使用可选(Optional)值。Optional定义的后一种情况表明,它可容纳一种数据 —可以是任何类型。

对于一个这样的定义 Optional< Int >— 它可以包含nil或Int值。非常简单和容易。那么,让我们用Swift的语法糖吧?并声明”age”和”height”变量,可以保留和整数或nil。

var age: Int? = nil
var height: Int? = 180

通过在数据类型之后加入?相当于你马上告诉编译器这个变量可能包含数字或者是nil。请注意,定义可选常量并没有意义的—常量是一个确定的不可变的值,但是可选说明它的值是可以是nil或者其他的值。

为了弄清楚到底是怎么回事,当你使用Optionals让我们来看看这是怎么回事幕后在上面的例子上。这一行:

var height: Int? = 180

等价于:

var height: Optional<Int> = Optional<Int>(180)

看来,一旦你知道发生了什么事情就很简单了,对不对?
“?”符号添加到数据类型来声明Optinal只是语法糖,实际上是在翻译上面的代码。

好吧,现在,我希望你能认识到什么是可选的(Optinal)数据类型,让我们一起来看看如何在代码中使用这些类型。

2. When to use ? and when !

让我们想象一下,你有一个简单的iPhone应用程序 — 一个基于的UIKit应用。你的视图控制器有一些代码,你想在屏幕的最上层显示一个新的视图控制器。你决定通过导航控制器Push一个新的。

希望你知道每一个的ViewController实例都有一个属性navigationController。如果你正在开发一个基于导航控制器的应用程序,你的应用程序的主视图控制器的这个属性被自动设置,你可以用它来push或pop其他的视图控制器。如果你使用的是单一的应用程序项目模板 — 将不会有自动为您创建一个导航控制器(navigationController),所以你的应用程序的默认视图控制器将不会有任何值存储在navigationController属性中。

我敢肯定你已经猜到了,这正是一个可选的数据类型的情况。如果你检查的UIViewController,你会看到属性定义为:

var navigationController: UINavigationController? { get }

因此,让我们回到我们的用例。如果你明确地知道一个事实,你的视图控制器永远有一个导航控制器,你可以继续前进,并且强制解析:

controller.navigationController!.pushViewController(myViewController, animated: true)

当你把一个!放在可选的属性名的后面,你告诉编译器,我不关心这个属性是不是可选的(optional),我知道,当这个代码执行时,这个可选值里会有一个确定的值,就像一个正常的数据类型。这样其实不是很好?如果一个视图控制器没有导航控制器?如果你以为navigationController始终有值这个假设是错误的?那么您的应用程序会崩溃—简单而丑陋的。

因此,使用!只有当你是101%肯定这是安全的。

假如你不确定是否总是存在一个导航控制器?那么你就可以使用?代替!

controller.navigationController?.pushViewController(myViewController, animated: true)

属性名后面的?告诉编译器,我不知道该属性是否有值或者是nil,因此:如果它有值就使用它,相反的,这个表达式就是nil。实际上,?确保只有当存在导航控制器的情况下,使用该属性。没有if判断或者其他任何处理。当你不在乎你是否有一个导航控制器或没有,只想当存在是做一些事情,那么这个语法是完美的。
但是,如果你想在没有navigationController的情况下做其他事情?例如,显示一个警告框来提示用户。
那么你要使用if let的表达方式。

3. When to use “if let”?

if let是Swift一个特殊的结构,使你可以检查一个可选值(Optional),如果它确实存储值,那么可以使用它解析后的数据做一些事情。让我们一起来看看:

if let nav = controller.navigationController {
    nav.pushViewController(myViewController, animated: true)
} else {
    //show an alert ot something else
}

if let 结构会解析controller.navigationController这个属性并且把解析出来的值放到常量“nav”中。你可以在if的第一个分支中直接使用它。注意,在分支内部你没有必要在使用?或者!来解析。你必须得知道“nav”的类型就是“UINavigationController”而不是可选类型(Optional type),因此你可以很直接地使用它。(你是否还记得navigationController原始的类型是UINavigationController?)

if let 结构在其他情况下也很有用。想象一下,你要多次调用navigationController这个属性而不是单一的调用一个方法,你不使用if let 结构那么你的代码看起来是这样:

controller.navigationController?.hidesBarsOnSwipe = true
controller.navigationController?.hidesBarsOnTap = true
controller.navigationController?.navigationBarHidden = false
controller.navigationController?.popToRootViewControllerAnimated(true)

这段代码的确有用但是你要重复地对这个属性做四次解析,如果用if let 结构你只需要解析一次而且更清晰,更高效:

if let nav = controller.navigationController {
  nav.hidesBarsOnSwipe = true
  nav.hidesBarsOnTap = true
  nav.navigationBarHidden = false
  nav.popToRootViewControllerAnimated(true)
}

很棒,不是吗?

最后一点 — nav在上面的例子是一个常量。你可以改变它的属性并且调用它的方法,但你不能改变nav本身的值。值得一提的是,你也可以这样使用if var nav = controller.navigationController。它的工作原理和if let相同,但你解析出来的是变量而不是常量。如果你有需要,可以改变它的值。

让我们来看看可选类型(Optional types)的最后的使用情境 — 类型转换。

4. When to use as? and when as

让我们继续想象UIKit的应用程序。让我们假设你在屏幕上显示一个新的视图控制器(例如使用这个方法presentViewController(_, animated:, completion:) )。

//your custom view controller
class MyViewController: UIViewController {
    var lastUpdated: NSDate? = nil
}

//in your master view controller
let myVC = MyViewController()
presentViewController(myVC, animated: true, completion: nil)

您定义了一个视图控制器,它有一个名为的“lastUpdated”额外的属性。让我们假设一旦这个控制器被呈现就改变这个属性。您可以通过主视图控制器上的presentedViewController属性访问当前正在屏幕上显示的控制器:

controller.presentedViewController!.title = "New Title"

presentedViewController的类型是 UIViewController?所以你可以很容易地解析并使用它。但是如果你应该如何改变“lastUpdated” 这个属性呢?这个属性是定义在“MyViewController”中而不是“UIViewController”?

你应该使用“as?”这个语法做转换,像这样:

let myVC = controller.presentedViewController as? MyViewController
myVC?.lastUpdated = NSDate()

as? 会根据给定的类型做转换,如果失败了会返回nil。这就是为什么一些函数的返回类型总是可选类型。当你不能保证类型转换一定成功时你应该用as?—例如,当你尝试将“AnyObject “或者”Any”转换成一个具体的类型时。
长话短说,当你不确定转换是否成功时用 as? 。

如果你101%肯定,转换会成功,在这种情况下可以省略?而只使用as.

swift 1.2以上版本对这一部分做了修改

对AnyObject直接使用as做类型转换会报错

1

为避免误解,同时学习最新的swift语言 原文后半部分略去,
有兴趣的可以参看这个
http://iphonedev.tv/blog/2015/2/9/swift-12-fixes-and-breaks-a-few-things-you-should-be-excited
end

EJB3.x JPA: When to use rollback() and setRollbackOnly()

After JTA was introduced for more than a decade ago, then later with the introduction of Bean-Manage...

Top 7 Questions to Ask When Hiring a Professional Packers and Movers in Jaipur

Relocating home from Jaipur toanother city of India? This would be the best decision to hire one of ...

How to create .lib file when you only have .dll and .h files

1. 原文地址:http://www.codeproject.com/KB/cpp/libfromdll.aspx 这篇讲解了DEF文件地结构,但附件中的工程编译不了。   2. Microso...

Git “fetch first”and ”non-fast-forward“ error when trying to push

参考 http://my.oschina.net/juwenz/blog/153350?fromerr=KEvNlIqT http://stackoverflow.com/questions/258...

How can selenium web driver get to know when the new window has opened and then resume its execution

http://stackoverflow.com/questions/9188343/how-can-selenium-web-driver-get-to-know-when-the-new-wind...

Compiling and linking error when using NDK r10 to build cocos2d-x v3.2

用ndk r10编译cocos2dx NDK r10 has problem, refer to [this ticket](https://code.google.com/p/androi...
  • shudaiu
  • shudaiu
  • 2014年08月09日 09:49
  • 1150

11. When to change dev/test sets and metrics 何时更改开发/测试集和评估指标(《MACHINE LEARNING YEARNING》翻译)

何时更改开发/测试集和评估指标当开始一个新项目时,我一般会试图快速选择一个 开发/测试集 ,因为这可以给团队制定一个明确的目标。我通常会要求我的团队在不到一周之内想出一个初始的开发/测试集和评估指标。...

When To Use Parallel-ForEach Or PLINQ.pdf

  • 2014年06月17日 11:12
  • 526KB
  • 下载

What To Do and Not To Do When 'shutdown immediate' Hangs [ID 375935.1]

What To Do and Not To Do When 'shutdown immediate' Hangs [ID 375935.1] Modified 22-JUL-2010     Type...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Swift Optionals: When to use if let, when ? and !, when as? and as
举报原因:
原因补充:

(最多只允许输入30个字)