蘋果三週前發佈了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中的可選項容許開發人員在編譯時發現潛在的問題,從而在運行時防止意外的錯誤。 一旦你習慣了語法,你會欣賞可選的美麗。
和往常同樣,咱們很樂意聽到您的反饋。 若是您對可選項有任何疑問或想分享您的想法,請隨時給咱們留言。