Swift語(yǔ)法總結(jié)-錯(cuò)誤處理,類型轉(zhuǎn)換腋妙,嵌套類型

1. 錯(cuò)誤處理

錯(cuò)誤處理(Error handling)是響應(yīng)錯(cuò)誤以及從錯(cuò)誤中恢復(fù)的過(guò)程默怨。Swift 提供了在運(yùn)行時(shí)對(duì)可恢復(fù)錯(cuò)誤的拋出、捕獲骤素、傳遞和操作的一等公民支持匙睹。

1.1 表示并拋出錯(cuò)誤

在 Swift 中,錯(cuò)誤用符合Error 協(xié)議的類型的值來(lái)表示济竹。這個(gè)空協(xié)議表明該類型可以用于錯(cuò)誤處理痕檬。
Swift 的枚舉類型尤為適合構(gòu)建一組相關(guān)的錯(cuò)誤狀態(tài),枚舉的關(guān)聯(lián)值還可以提供錯(cuò)誤狀態(tài)的額外信息

enum VendingMachineError: Error {
  case invalidSelection //選擇無(wú)效
  case insufficientFunds(coinsNeeded: Int) //金額不足
  case outOfStock //缺貨
}
1.2 處理錯(cuò)誤

某個(gè)錯(cuò)誤被拋出時(shí)送浊,附近的某部分代碼必須負(fù)責(zé)處理這個(gè)錯(cuò)誤梦谜,例如糾正這個(gè)問(wèn)題、嘗試另外一種方式袭景、或是向用戶報(bào)告錯(cuò)誤唁桩。

1.2.1 用 throwing 函數(shù)傳遞錯(cuò)誤

為了表示一個(gè)函數(shù)、方法或構(gòu)造器可以拋出錯(cuò)誤耸棒,在函數(shù)聲明的參數(shù)列表之后加上throws 關(guān)鍵字荒澡。一個(gè)標(biāo)有throws 關(guān)鍵字的函數(shù)被稱作throwing 函數(shù)。如果這個(gè)函數(shù)指明了返回值類型与殃, throws 關(guān)鍵詞需要寫在箭頭( -> )的前面单山。

func canThrowErrors() throws -> String
func cannotThrowErrors() -> String

一個(gè) throwing 函數(shù)可以在其內(nèi)部拋出錯(cuò)誤,并將錯(cuò)誤傳遞到函數(shù)被調(diào)用時(shí)的作用域幅疼。

注意
只有 throwing 函數(shù)可以傳遞錯(cuò)誤米奸。任何在某個(gè)非 throwing 函數(shù)內(nèi)部拋出的錯(cuò)誤只能在函數(shù)內(nèi)部處理。

struct Item {
    var price: Int
    var count: Int
}
class VendingMachine {
    var inventory = [
        "Candy Bar": Item(price: 12, count: 7),
        "Chips": Item(price: 10, count: 4),
        "Pretzels": Item(price: 7, count: 11)
    ]
    var coinsDeposited = 0

    func dispenseSnack(snack: String) {
        print("Dispensing \(snack)")
    }

    func vend(itemNamed name: String) throws {

        guard let item = inventory[name] else {
            throw VendingMachineError.InvalidSelection
        }

        guard item.count > 0 else {
            throw VendingMachineError.OutOfStock
        }

        guard item.price <= coinsDeposited else {
            throw VendingMachineError.InsufficientFunds(coinsNeeded: item.price - coinsDeposited)
        }

        coinsDeposited -= item.price
        var newItem = item
        newItem.count -= 1
        inventory[name] = newItem
        print("Dispensing \(name)")
    }
}

在vend(itemNamed:) 方法的實(shí)現(xiàn)中使用了guard 語(yǔ)句來(lái)提前退出方法爽篷,確保在購(gòu)買某個(gè)物品所需的條件中躏升,有任一條件不滿足時(shí),能提前退出方法并拋出相應(yīng)的錯(cuò)誤狼忱。由于throw 語(yǔ)句會(huì)立即退出方法膨疏,所以物品只有在所有條件都滿足時(shí)才會(huì)被售出一睁。

1.2.2 用 Do-Catch 處理錯(cuò)誤

可以使用一個(gè)do-catch 語(yǔ)句運(yùn)行一段閉包代碼來(lái)處理錯(cuò)誤。如果在do 子句中的代碼拋出了一個(gè)錯(cuò)誤佃却,這個(gè)錯(cuò)誤會(huì)與catch 子句做匹配者吁,從而決定哪條子句能處理它。

do {
    try expression
    statements
} catch pattern 1 {
    statements
} catch pattern 2 where condition {
    statements
}
1.2.3 將錯(cuò)誤轉(zhuǎn)換成可選值

可以使用try? 通過(guò)將錯(cuò)誤轉(zhuǎn)換成一個(gè)可選值來(lái)處理錯(cuò)誤饲帅。如果在評(píng)估try? 表達(dá)式時(shí)一個(gè)錯(cuò)誤被拋出复凳,那么表達(dá)式的值就是nil

func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
    return nil
}
1.2.4 禁用錯(cuò)誤傳遞

有時(shí)你知道某個(gè)throwing 函數(shù)實(shí)際上在運(yùn)行時(shí)是不會(huì)拋出錯(cuò)誤的,在這種情況下灶泵,你可以在表達(dá)式前面寫try! 來(lái)禁用錯(cuò)誤傳遞育八,這會(huì)把調(diào)用包裝在一個(gè)不會(huì)有錯(cuò)誤拋出的運(yùn)行時(shí)斷言中。如果真的拋出了錯(cuò)誤赦邻,你會(huì)得到一個(gè)運(yùn)行時(shí)錯(cuò)誤髓棋。

1.3 指定清理操作

可以使用defer 語(yǔ)句在即將離開當(dāng)前代碼塊時(shí)執(zhí)行一系列語(yǔ)句。該語(yǔ)句讓你能執(zhí)行一些必要的清理工作惶洲,不管是以何種方式離開當(dāng)前代碼塊的——無(wú)論是由于拋出錯(cuò)誤而離開按声,還是由于諸如return 或者break 的語(yǔ)句。例如恬吕,你可以用defer 語(yǔ)句來(lái)確保文件描述符得以關(guān)閉签则,以及手動(dòng)分配的內(nèi)存得以釋放。

defer 語(yǔ)句將代碼的執(zhí)行延遲到當(dāng)前的作用域退出之前铐料。該語(yǔ)句由defer 關(guān)鍵字和要被延遲執(zhí)行的語(yǔ)句組成渐裂。延遲執(zhí)行的語(yǔ)句不能包含任何控制轉(zhuǎn)移語(yǔ)句,例如break 或是return 語(yǔ)句钠惩,或是拋出一個(gè)錯(cuò)誤芯义。延遲執(zhí)行的操作會(huì)按照它們被指定時(shí)的順序的相反順序執(zhí)行——也就是說(shuō),第一條defer 語(yǔ)句中的代碼會(huì)在第二條defer 語(yǔ)句中的代碼被執(zhí)行之后才執(zhí)行妻柒,以此類推扛拨。

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
        close(file)
    }
    while let line = try file.readline() {
        // 處理文件。
    }
    // close(file) 會(huì)在這里被調(diào)用举塔,即作用域的最后绑警。
    }
}

上面的代碼使用一條defer 語(yǔ)句來(lái)確保open(:) 函數(shù)有一個(gè)相應(yīng)的對(duì)close(:) 函數(shù)的調(diào)用。

注意
即使沒(méi)有涉及到錯(cuò)誤處理央渣,你也可以使用defer 語(yǔ)句计盒。

2. 類型轉(zhuǎn)換

<1>類型轉(zhuǎn)換可以判斷實(shí)例的類型,也可以將實(shí)例看做是其父類或者子類的實(shí)例芽丹。
<2>類型轉(zhuǎn)換在 Swift 中使用is 和as 操作符實(shí)現(xiàn)北启。這兩個(gè)操作符提供了一種簡(jiǎn)單達(dá)意的方式去檢查值的類型或者轉(zhuǎn)換它的類型。
<3>你也可以用它來(lái)檢查一個(gè)類型是否實(shí)現(xiàn)了某個(gè)協(xié)議

2.1 定義一個(gè)類層次作為例子

你可以將類型轉(zhuǎn)換用在類和子類的層次結(jié)構(gòu)上,檢查特定類實(shí)例的類型并且轉(zhuǎn)換這個(gè)類實(shí)例的類型成為這個(gè)層次結(jié)構(gòu)中的其他類型

2.2 檢查類型

用類型檢查操作符( is )來(lái)檢查一個(gè)實(shí)例是否屬于特定子類型咕村。若實(shí)例屬于那個(gè)子類型场钉,類型檢查操作符返回true ,否則返回false 懈涛。

var movieCount = 0
var songCount = 0
for item in library {
    if item is Movie {
        movieCount += 1
    } else if item is Song {
        songCount += 1
    }
}
print("Media library contains \(movieCount) movies and \(songCount) songs")
// 打印 “Media library contains 2 movies and 3 songs
2.3 向下轉(zhuǎn)型

某類型的一個(gè)常量或變量可能在幕后實(shí)際上屬于一個(gè)子類逛万。當(dāng)確定是這種情況時(shí),你可以嘗試向下轉(zhuǎn)到它的子類型批钠,用類型轉(zhuǎn)換操作符( as? 或as! )宇植。

for item in library {
    if let movie = item as? Movie {
        print("Movie: '\(movie.name)', dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: '\(song.name)', by \(song.artist)")
    }
}
// Movie: 'Casablanca', dir. Michael Curtiz

注意
轉(zhuǎn)換沒(méi)有真的改變實(shí)例或它的值。根本的實(shí)例保持不變埋心;只是簡(jiǎn)單地把它作為它被轉(zhuǎn)換成的類型來(lái)使用指郁。

2.4 Any 和 AnyObject 的類型轉(zhuǎn)換

Swift 為不確定類型提供了兩種特殊的類型別名:
? Any 可以表示任何類型,包括函數(shù)類型拷呆。
? AnyObject 可以表示任何類類型的實(shí)例闲坎。

注意
Any 類型可以表示所有類型的值,包括可選類型洋腮。Swift 會(huì)在你用Any 類型來(lái)表示一個(gè)可選值的時(shí)候,給你一個(gè)警告手形。如果你確實(shí)想使用Any 類型來(lái)承載可選值啥供,你可以使用as 操作符顯示轉(zhuǎn)換為Any ,如下所示:

let optionalNumber: Int? = 3
things.append(optionalNumber) // 警告
things.append(optionalNumber as Any) // 沒(méi)有警告
3. 嵌套類型

枚舉常被用于為特定類或結(jié)構(gòu)體實(shí)現(xiàn)某些功能库糠。類似的伙狐,枚舉可以方便的定義工具類或結(jié)構(gòu)體,從而為某個(gè)復(fù)雜的類型所使用瞬欧。為了實(shí)現(xiàn)這種功能贷屎,Swift 允許你定義嵌套類型,可以在支持的類型中定義嵌套的枚舉艘虎、類和結(jié)構(gòu)體唉侄。

3.1 嵌套類型實(shí)踐

要在一個(gè)類型中嵌套另一個(gè)類型,將嵌套類型的定義寫在其外部類型的{} 內(nèi)野建,而且可以根據(jù)需要定義多級(jí)嵌套属划。

3.2 引用嵌套類型

在外部引用嵌套類型時(shí),在嵌套類型的類型名前加上其外部類型的類型名作為前綴:

let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue
// 紅心符號(hào)為 “?”
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末候生,一起剝皮案震驚了整個(gè)濱河市同眯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唯鸭,老刑警劉巖须蜗,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡明肮,警方通過(guò)查閱死者的電腦和手機(jī)菱农,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)晤愧,“玉大人大莫,你說(shuō)我怎么就攤上這事」俜荩” “怎么了只厘?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)舅巷。 經(jīng)常有香客問(wèn)我羔味,道長(zhǎng),這世上最難降的妖魔是什么钠右? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任赋元,我火速辦了婚禮,結(jié)果婚禮上飒房,老公的妹妹穿的比我還像新娘搁凸。我一直安慰自己,他們只是感情好狠毯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布护糖。 她就那樣靜靜地躺著,像睡著了一般嚼松。 火紅的嫁衣襯著肌膚如雪嫡良。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天献酗,我揣著相機(jī)與錄音寝受,去河邊找鬼。 笑死罕偎,一個(gè)胖子當(dāng)著我的面吹牛很澄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播颜及,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痴怨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了器予?” 一聲冷哼從身側(cè)響起浪藻,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乾翔,沒(méi)想到半個(gè)月后爱葵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體施戴,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年萌丈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赞哗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辆雾,死狀恐怖肪笋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情度迂,我是刑警寧澤藤乙,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站惭墓,受9級(jí)特大地震影響坛梁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腊凶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一划咐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钧萍,春花似錦褐缠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至弛秋,卻和暖如春器躏,著一層夾襖步出監(jiān)牢的瞬間俐载,已是汗流浹背蟹略。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遏佣,地道東北人挖炬。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像状婶,于是被迫代替她去往敵國(guó)和親意敛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容