Optional變量初學者指南

蘋果三週前發佈了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中的可選項容許開發人員在編譯時發現潛在的問題,從而在運行時防止意外的錯誤。 一旦你習慣了語法,你會欣賞可選的美麗。

和往常同樣,咱們很樂意聽到您的反饋。 若是您對可選項有任何疑問或想分享您的想法,請隨時給咱們留言。

相關文章
相關標籤/搜索