苹果三周前发布了Swift。 从那时起,我一直在阅读Swift的官方指南,并在Xcode 6测试版中使用。 我开始喜欢Swift的简单和语法。 与个人团队一块儿,我仍然在研究新的语言,并看看它与Objective-C(一种30岁的编程语言)相好比何。 同时,咱们正在努力工做,看看咱们如何教初学者,帮助社区轻松应对Swift。编程
两周前,咱们介绍了Swift的基础知识。 在接下来的几周内,咱们将编写一系列教程,以涵盖Swift中的许多新功能。 本周,咱们先来看看Optional变量。安全
Optionals 概览框架
我在上一篇文章中提到了可选项,但没有详细介绍。 那么什么是可选项? 在Swift中声明变量时,默认状况下它们被指定为非可选项。 换句话说,您必须为变量分配非空值。 若是您尝试将一个零值设置为非可选项,编译器会说:“你不能设置一个空值!”。编程语言
var message: String = "Swift is awesome!" // OK message = nil // compile-time error
固然,错误消息不是那么用户友好,但它相似“__conversion’ that accepts the supplied arguments“。 一样适用于在类中声明属性时。 默认状况下,属性被指定为非可选属性。函数
class Messenger { var message1: String = "Swift is awesome!" // OK var message2: String // compile-time error }
您将收到message2的编译时错误,由于它没有分配初始值。 对于来自Objective-C的用户,可能会有点惊讶。 在Objective-C中,在将nil分配给变量或声明没有初始值的属性时,不会获得任何编译时错误:测试
NSString *message = @"Objective-C will never die!"; message = nil; class Messenger { NSString *message1 = @"Objective will never die!"; NSString *message2; }
可是,这并不意味着您没法在Swift中分配初始值时声明属性。 Swift引入了可选类型来表示没有值。 它是经过添加问号来定义的? 运算符类型声明后。 这是一个例子:spa
class Messenger { var message1: String = "Swift is awesome!" // OK var message2: String? // OK }
当变量被定义为可选时,仍然能够赋值。 可是,若是变量象上面的代码同样没有分配任何值,其值将自动默认为nil。设计
为何要用 Optionals?code
Swift是为安全而设计的。 正如苹果所说,可选项是Swift是一种类型的安全语言的例子。 从上面的例子能够看出,Swift的可选项提供编译时检查,能够防止在运行时发生一些常见的编程错误。 咱们来看下面的例子,你将更好地了解可选项的功能。blog
在Objective-C中考虑如下方法:
- (NSString *)findStockCode:(NSString *)company { if ([company isEqualToString:@"Apple"]) { return @"AAPL"; } else if ([company isEqualToString:@"Google"]) { return @"GOOG"; } return nil; }
您可使用findStockCode:方法获取特定上市公司的股票代码。 为了演示目的,该方法只返回您的Apple和Google的股票代码。 对于其余输入,它返回空值。
假设该方法在同一个类中定义,咱们使用它:
NSString *stockCode = [self findStockCode:@"Facebook"]; // nil is returned NSString *text = @"Stock Code - "; NSString *message = [text stringByAppendingString:stockCode]; // runtime error NSLog(@"%@", message);
该代码能够正确编译,可是当该方法对Facebook返回nil时,运行该应用程序会抛出运行时异常。
使用Swift的可选项,它会在编译时显示错误,而不是在运行时发现错误。 若是咱们在Swift中重写上述示例,它将以下所示:
func findStockCode(company: String) -> String? { if (company == "Apple") { return "AAPL" } else if (company == "Google") { return "GOOG" } return nil } var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " let message = text + stockCode // compile-time error println(message)
stockCode被定义为可选项。 这意味着它能够包含字符串或空值。 您没法执行上述代码,由于编译器检测到潜在错误(“可选类型String的值未展开”),并通知您进行更正。
从示例中能够看出,Swift的可选功能增强了空值检查,为开发人员提供了编译时的指引。 显然,使用可选项有助于更好的代码质量。
可选变量解包
那么咱们该如何使代码工做? 显然,咱们须要测试stockCode是否包含一个空值。 咱们修改以下:
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " if stockCode { let message = text + stockCode! println(message) }
就像Objective-C对应的,咱们使用if来查看可选项是否包含一个值。 一旦咱们知道可选项必须包含一个值,咱们经过在可选名称的末尾放置一个感叹号(!)来解开它。 在Swift,这被称为强制展开。 你用! 操做符打开可选项并显示底层值。
参考上面的例子,咱们只在nil-check以后解开“stockCode”可选项。 咱们知道可选量必须包含非零值,而后才能使用! 操做符。 始终建议确保可选项在解开以前包含一个值。
可是若是咱们忘记下面的验证怎么办?
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " let message = text + stockCode! // runtime error
将不会有编译时错误。 编译器假定可选的包含一个值,由于使用了强制展开。 运行应用程序时,将抛出运行时错误,并显示如下消息:
fatal error: Can’t unwrap Optional.None
可选绑定
除了强制解包以外,可选绑定是一种更简单和推荐的方式来打开可选的。 您使用可选绑定来检查可选项是否包含值。 若是它包含一个值,将其解开并将其放入临时常量或变量中。
没有比使用示例更好的解释可选绑定的方式。 咱们将上一个示例中的示例代码转换为可选绑定:
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " if let tempStockCode = stockCode { let message = text + tempStockCode println(message) }
“if let”(或“if var”)是可选绑定的两个关键字。 通俗地,代码说“若是stockCode包含一个值,将其解开,将其值设置为tempStockCode并执行条件块。 不然,只是跳过块“。 因为tempStockCode是一个新的常量,您再也不须要使用! 后缀访问其值。
您能够经过评估if语句中的函数来进一步简化代码:
let text = "Stock Code - " if var stockCode = findStockCode("Apple") { let message = text + stockCode println(message) }
这里的stockCode不是可选的,没有必要使用! 后缀访问条件块中的值。 若是从函数返回nil值,则不会执行该块。
可选链
在解释可选连接以前,让咱们稍微调整一下原来的例子。 咱们建立一个名为Stock的新类,其代码和价格属性是可选的。 findStockCode函数被修改成返回Stock类而不是String。
class Stock { var code: String? var price: Double? } func findStockCode(company: String) -> Stock? { if (company == "Apple") { let aapl: Stock = Stock() aapl.code = "AAPL" aapl.price = 90.32 return aapl } else if (company == "Google") { let goog: Stock = Stock() goog.code = "GOOG" goog.price = 556.36 return goog } return nil }
咱们重写原始示例以下。 咱们首先经过调用findStockCode函数找到股票代码/符号。 而后咱们计算购买100股股票所需的总成本。
if let stock = findStockCode("Apple") { if let sharePrice = stock.price { let totalCost = sharePrice * 100 println(totalCost) } }
因为findStockCode()的返回值是可选的,咱们使用可选绑定来检查它是否包含实际值。 显然,股票类的价格属性是可选的。 咱们再次使用“if let”语句来测试stock.price是否包含非零值。
上述代码没有任何错误。 您可使用可选连接来简化代码,而不是编写嵌套的“if set”。 该功能容许咱们链接多个可选项与“?”操做符。 这是代码的简化版本:
if let sharePrice = findStockCode("Apple")?.price { let totalCost = sharePrice * 100 println(totalCost) }
可选连接提供了访问价格价值的另外一种方法。 该代码如今看起来更清洁和更简单。 这里我只是介绍可选连接的基础知识。 您能够在Apple Swift指南中找到有关可选连接的更多信息。
Swift和Objective-C互操做性
Swift的可选功能很是强大,尽管可能须要一些时间来习惯语法。 可选项能够帮助您清楚代码可使用的值,并避免错过无效。
Swift旨在与Objective-C API进行交互。 每当您须要与UIKit或其余框架API进行交互时,您必定会遇到可选项。 如下是实现表视图时遇到的一些可选项:
func numberOfSectionsInTableView(tableView: UITableView?) -> Int { // Return the number of sections. return 1 } func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { // Return the number of rows in the section. return recipes.count } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell cell.textLabel.text = recipes[indexPath.row] return cell }
概要
了解可选项如何工做相当重要,这就是为何咱们将完整的文章用于可选项。 Swift中的可选项容许开发人员在编译时发现潜在的问题,从而在运行时防止意外的错误。 一旦你习惯了语法,你会欣赏可选的美丽。
和往常同样,咱们很乐意听到您的反馈。 若是您对可选项有任何疑问或想分享您的想法,请随时给咱们留言。