精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

全面解析Swift 2錯誤處理技術

譯文
移動開發 iOS
自從Swift 1開始就提供了錯誤處理技術支持;這種技術是受來自于Objective-C的啟發而開發出的。Swift 2在這方面的改進使得處理您的應用程序中的意外狀態和條件更加簡單直接。

 自從Swift 1開始就提供了錯誤處理技術支持;這種技術是受來自于Objective-C的啟發而開發出的。Swift 2在這方面的改進使得處理您的應用程序中的意外狀態和條件更加簡單直接。

就像其他普通的編程語言一樣,Swift中的錯誤處理技術也存在不同類型,具體情況則要取決于遇到的錯誤類型和您的應用程序的總體結構。

本教程將帶您通過具體的例子來介紹如何最有效地處理常見的錯誤情況。你還會看到如何升級早期版本Swift編寫的項目中的錯誤處理模塊。文章***,將集中介紹未來版本的Swift可能提供的錯誤處理技術!

【注意】本教程假定您已熟悉使用Swift 2語法,特別是枚舉(enumberations)和可選值(optionals)。如果你需要復習一下這些概念,建議您閱讀Greg Heo的文章“What’s New in Swift 2”。

接下來,就讓我們開始踏上Swift 2錯誤處理技術的學習征程,你一定會體會到不一樣的樂趣的!

簡介

本教程提供了兩個初學者案例供大家學習使用,它們的下載地址分別是:https://cdn4.raywenderlich.com/wp-content/uploads/2016/04/Avoiding-Errors-with-nil-Starter.playground-1.ziphttps://cdn4.raywenderlich.com/wp-content/uploads/2016/04/Avoiding-Errors-with-Custom-Handling-Starter.playground-1.zip

為了跟蹤本文中的實例代碼,請下載這兩個示例工程。

首先,請使用Xcode打開***個初學者案例Errors with nil。通讀工程中的代碼,你會看到有幾個類、結構和枚舉定義。

請注意代碼的以下部分:

  1. protocol MagicalTutorialObject { 
  2.  
  3. var avatar: String { get } 
  4.  

這個協議適用于本教程中使用的所有類和結構,它用于為工程中的每一個對象有關信息提供可視化描述——打印到控制臺中。

  1. enum MagicWords: String { 
  2.  
  3. case Abracadbra = "abracadabra" 
  4.  
  5. case Alakazam = "alakazam" 
  6.  
  7. case HocusPocus = "hocus pocus" 
  8.  
  9. case PrestoChango = "presto chango" 
  10.  

此枚舉定義了一些可用于創建一個魔法的咒語。

  1. struct Spell: MagicalTutorialObject { 
  2.  
  3. var magicWords: MagicWords = .Abracadbra 
  4.  
  5. var avatar = "*" 
  6.  

這是一個魔法的基本構建塊。默認情況下,它的初始化咒語值為“Abracadbra”。

現在,您已經熟悉了我們要介紹的例子中的一些基本術語,那么接下來您要開始施行一些“魔法”了。

為什么要關注錯誤處理

錯誤處理是一種以優雅方式失敗的藝術。

——出自《Swift Apprentice》一書的第12章(“錯誤處理”)

好的錯誤處理方法有助于增強最終用戶和軟件維護人員的體驗,使其更容易地查明問題、 問題原因及其可能產生的嚴重后果。代碼中錯誤處理得越具體,問題就越容易診斷。錯誤處理也可以讓系統用適當的方式拋出錯誤,從而不至于挫敗或擾亂用戶。

但并不是需要處理一切錯誤。如果程序員不處理,語言功能本身也可能會使您完全避免某些類別的錯誤。作為一般規則,如果你能避免錯誤的可能性,那么請遵循這樣的設計思路。如果你不能避免潛在的錯誤條件,那么顯式處理錯誤是你***的選擇。

使用nil避免Swift錯誤

由于Swift提供了優雅的可選項(Optionals)處理能力;所以,在你期望值出現但未提供值的地方您完全可以避免錯誤條件。作為一個聰明的程序員,你可以操縱此功能:通過一個錯誤條件判斷故意返回nil。這種方法最適合用于當你到達一個錯誤狀態但你不必采取任何措施的情形;也就是說,你選擇不采取措施而不是采取緊急措施。

兩個典型的使用nil避免Swift錯誤的例子是可失敗構造器和guard語句。

可失敗構造器(failable initializer)

可失敗構造器能夠防止一個對象的創建——除非已提供了足夠的信息。在Swift 2以前(以及在其他語言中),這一功能通常是通過工廠方法模式實現的。

Swift使用這種模式的一個示例在createWithMagicWords方法中就會看到:

  1. static func createWithMagicWords(words: String) -> Spell? { 
  2.  
  3. if let incantation = MagicWords(rawValue: words) { 
  4.  
  5. var spell = Spell() 
  6.  
  7. spell.magicWords = incantation 
  8.  
  9. return spell 
  10.  
  11.  
  12. else { 
  13.  
  14. return nil 
  15.  
  16.  

上述初始化器試圖使用提供的咒語創建一個魔法(spell);但如果言語不是咒語(magic words),改以返回nil。

你可以在本教程***部的代碼中觀察魔法的創建來查看這種方法的使用:

你會注意到: first使用咒語“abracadabra”成功創建一個魔法,而咒語“ascendio”并不會產生這種效果,并返回second的值為nil。

工廠方法是一種老式的編程風格。其實,在Swift中有更好的方式來實現同樣的事情。為此,你只需使用一個可失敗構造器而不是工廠方法來更新spell擴展即可。

于是,你可以刪除createWithMagicWords(_:)方法并把它替換為以下內容:

  1. init?(words: String) { 
  2.  
  3. if let incantation = MagicWords(rawValue: words) { 
  4.  
  5. self.magicWords = incantation 
  6.  
  7.  
  8. else { 
  9.  
  10. return nil 
  11.  
  12.  

在這里,你簡化了代碼——并沒有顯式創建和返回spell對象。

給first和second賦值的語句行現在會拋出編譯時錯誤:

  1. let first = Spell.createWithMagicWords("abracadabra"
  2.  
  3. let second = Spell.createWithMagicWords("ascendio"

你需要更改這些語句——使用新的初始化器。為此,你只需要使用以下內容替換上面的代碼行即可:

  1. let first = Spell(words: "abracadabra"
  2.  
  3. let second = Spell(words: "ascendio"

此后,所有錯誤應修復完畢,再編譯示例工程應沒有什么錯誤。這樣修改以后,您的代碼整潔多了——但是其實你可以做得比這更好!

Guard語句

guard是一種斷言某事是否為真實的快速方法。然后,如果檢查失敗,您可以執行事先設計的代碼塊。

Guard是Swift 2引入的,通常用于通過調用堆棧以冒泡法處理錯誤,最終錯誤將得到處理。Guard語句允許提前退出一個函數或方法;這使得程序員更清楚對于剩下的要運行的處理邏輯需要存在哪些條件。

為了進一步精簡魔法的可失敗構造器,我們再來使用guard方法修改一下上面代碼:

  1. init?(words: String) { 
  2.  
  3. guard let incantation = MagicWords(rawValue: words) else { 
  4.  
  5. return nil 
  6.  
  7.  
  8. self.magicWords = incantation 
  9.  

這樣修改后,就沒有必要再在一個單獨的行上使用一個單獨的else子句;而且,失敗的情況也更加明顯,因為它現在位于初始化程序的頂部。

請注意,***和第二個魔法常量的值沒有改變,但代碼卻變得更為精簡了。

使用定制處理器避免錯誤

上面通過精簡魔法的可失敗構造器并通過巧妙地使用nil已經可以避免一些錯誤。接下來,讓我們來處理一些更復雜的錯誤。

為了學習接下來的錯誤處理技術,請打開工程Avoiding-Errors-with-Custom-Handling-Starter.playground-1。

請注意下面代碼中的特征:

  1. struct Spell: MagicalTutorialObject { 
  2.  
  3. var magicWords: MagicWords = .Abracadbra 
  4.  
  5. var avatar = "*" 
  6.  
  7. init?(words: String) { 
  8.  
  9. guard let incantation = MagicWords(rawValue: words) else { 
  10.  
  11. return nil 
  12.  
  13.  
  14. self.magicWords = incantation 
  15.  
  16.  
  17. init?(magicWords: MagicWords) { 
  18.  
  19. self.magicWords = magicWords 
  20.  
  21.  

這里定義的是Spell的構造器,我們對之作了簡要修改以匹配您在本教程的***部分所完成的工作。此外,請注意這里還使用了MagicalTutorialObject協議和另外一個為了方便使用而引入的可失敗構造器。

  1. protocol Familiar: MagicalTutorialObject { 
  2.  
  3. var noise: String { get } 
  4.  
  5. var name: String? { get set } 
  6.  
  7. init() 
  8.  
  9. init(name: String?) 
  10.  

這里的Familiar協議將適用于各類寵物(如蝙蝠和蟾蜍,為女巫所豢養和驅使),在本文第二個示例工程中一直這樣使用。

接下來看女巫(Witch)的定義:

  1. struct Witch: MagicalBeing { 
  2.  
  3. var avatar = "*" 
  4.  
  5. var name: String? 
  6.  
  7. var familiar: Familiar? 
  8.  
  9. var spells: [Spell] = [] 
  10.  
  11. var hat: Hat? 
  12.  
  13. init(name: String?, familiar: Familiar?) { 
  14.  
  15. self.name = name 
  16.  
  17. self.familiar = familiar 
  18.  
  19. if let s = Spell(magicWords: .PrestoChango) { 
  20.  
  21. self.spells = [s] 
  22.  
  23.  
  24.  
  25. init(name: String?, familiar: Familiar?, hat: Hat?) { 
  26.  
  27. self.init(namename, familiar: familiar) 
  28.  
  29. self.hat = hat 
  30.  
  31.  
  32. func turnFamiliarIntoToad() -> Toad { 
  33.  
  34. if let hat = hat { 
  35.  
  36. if hat.isMagical { // When have you ever seen a Witch perform a spell without her magical hat on ? :] 
  37.  
  38. if let familiar = familiar { // Check if witch has a familiar 
  39.  
  40. if let toad = familiar as? Toad { // Check if familiar is already a toad - no magic required 
  41.  
  42. return toad 
  43.  
  44. else { 
  45.  
  46. if hasSpellOfType(.PrestoChango) { 
  47.  
  48. if let name = familiar.name { 
  49.  
  50. return Toad(namename
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58. return Toad(name"New Toad") // This is an entirely new Toad. 
  59.  
  60.  
  61. func hasSpellOfType(type: MagicWords) -> Bool { // Check if witch currently has appropriate spell in their spellbook 
  62.  
  63. return spells.contains { $0.magicWords == type } 
  64.  
  65.  

現在,讓我們簡單作一下總結:

初始化女巫:使用name和familiar參數,或者再添加一個hat參數。

一個女巫知道有限數量的魔法;這些存儲魔法在spells中,spells是一個魔法對象的數組。

每一個巫婆似乎都有一個嗜好,即在turnFamiliarIntoToad()方法中通過使用PrestoChango咒語把她的寵物變成一只癩蛤蟆。

請注意上面方法turnFamiliarIntoToad()中的縮進字符的數量。此外,你還應當注意:該方法中如果有任何差錯,將返回一只全新的蟾蜍。這似乎令人費解(而且有些錯誤!)。在下一節中,通過自定義錯誤處理技術您會完全明白這段代碼的。

使用重構技術

在上面的turnFamiliarIntoToad()方法中使用了多級嵌套語句來控制程序流程,而閱讀這樣的嵌套代碼相當費勁。

如你前面看到的,Guard語句和多個可選綁定的使用有助于清除上面金字塔式復雜代碼。然而,利用do-catch機制,通過從錯誤狀態處理中解耦控制流能夠徹底消除這一問題。

do-catch機制通常出現在以下關鍵字前后:

throws

do

catch

try

defer

ErrorType

若要查看這些關鍵字的實際使用,你要拋出多個自定義錯誤。首先,你要定義你希望處理的語句,你可以通過一個枚舉來列出一切可能出錯的內容。

然后,將下面的代碼添加到你的示例工程(一個與游樂場內容有關的程序)的女巫(Witch)定義的上方:

  1. enum ChangoSpellError: ErrorType { 
  2.  
  3. case HatMissingOrNotMagical 
  4.  
  5. case NoFamiliar 
  6.  
  7. case FamiliarAlreadyAToad 
  8.  
  9. case SpellFailed(reason: String) 
  10.  
  11. case SpellNotKnownToWitch 
  12.  

請注意與ChangoSpellError有關的兩點:

它符合ErrorType協議,這是在Swift語言中定義錯誤時的必要條件。

在SpellFailed情形下,可以針對魔法失敗通過一個關聯值指定一個自定義原因。

接下來,把throws關鍵字添加到方法簽名中,以指示調用此方法時可能會發生錯誤:

  1. func turnFamiliarIntoToad() throws -> Toad { 

然后,在MagicalBeing協議上也作一下更新:

  1. protocol MagicalBeing: MagicalTutorialObject { 
  2.  
  3. var name: String? { get set } 
  4.  
  5. var spells: [Spell] { get set } 
  6.  
  7. func turnFamiliarIntoToad() throws -> Toad 
  8.  

既然你已經列出所有錯誤狀態,接下來你可以重構turnFamiliarIntoToad()方法。

處理帽子相關錯誤

首先,修改下面的語句以確保女巫戴著她最重要的帽子,把語句:

  1. if let hat = hat { 

修改為:

  1. guard let hat = hat else { 
  2.  
  3. throw ChangoSpellError.HatMissingOrNotMagical 
  4.  

【注意】不要忘記刪除方法底部的}符號;否則工程將會出現編譯錯誤!

下一行包含一個布爾值檢查,也是與帽子相關的:

  1. if hat.isMagical { 

您可以選擇添加一個單獨的guard語句來執行這項檢查;但是,把一組檢查統一放在一行代碼中更為清楚。因此,你可以更改***個的guard語句,像下面這樣:

  1. guard let hat = hat where hat.isMagical else { 
  2.  
  3. throw ChangoSpellError.HatMissingOrNotMagical 
  4.  

現在,經這樣一修改,也一并消除了if hat.isMagical {檢查部分。

在下一節中,你會繼續解除那種成金字塔形可怕的條件語句。

處理Familiar有關錯誤

【譯者注】在本文中,我把“familiar”翻譯為“寵物”,即前面為女巫所豢養和驅駛的各種小動物。

接下來,讓我們修改檢測是否女巫是否含有familiar的語句,即把語句:

  1. if let familiar = familiar { 

修改為從另一個guard語句中拋出一個錯誤:

  1. guard let familiar = familiar else { 
  2.  
  3. throw ChangoSpellError.NoFamiliar 
  4.  

目前,我們先忽略發生的任何錯誤,因為你接下來的代碼更改會使它們消失。

處理Toad相關錯誤

在下一行中,如果巫婆想要對毫無戒心的兩棲類施加turnFamiliarIntoToad()咒語的話,你需要返回現有的蟾蜍,但使用一種明確的錯誤會更好地告知她犯的錯誤。為此,把以下內容:

  1. if let toad = familiar as? Toad { 
  2.  
  3. return toad 
  4.  

修改成如下語句:

  1. if familiar is Toad { 
  2.  
  3. throw ChangoSpellError.FamiliarAlreadyAToad 
  4.  

注意到,這里把as?修改為is,從而可以更簡潔地檢查與協議的一致性,而不一定需要使用結果。關鍵字is還可以用于更普遍形式的類型比較。如果你有興趣更多地學習is和as,建議你閱讀蘋果官網中《Swift編程語言》的類型轉換部分(https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html)。

使用上面技術,我們就可以把else子句里面的內容放到else子句外面,從而刪除掉else。

處理魔法相關錯誤

***,對hasSpellOfType(type:)方法的調用可以確保女巫在她的魔法書中存在適當的魔法。為此,我們把下面的代碼:

  1. if hasSpellOfType(.PrestoChango) { 
  2.  
  3. if let toad = f as? Toad { 
  4.  
  5. return toad 
  6.  
  7.  

更改為如下代碼:

  1. guard hasSpellOfType(.PrestoChango) else { 
  2.  
  3. throw ChangoSpellError.SpellNotKnownToWitch 
  4.  
  5.  
  6. guard let name = familiar.name else { 
  7.  
  8. let reason = "Familiar doesn’t have a name." 
  9.  
  10. throw ChangoSpellError.SpellFailed(reason: reason) 
  11.  
  12.  
  13. return Toad(namename

現在,您可以刪除***一行代碼,這是沒有問題的,即刪除下面一行:

  1. return Toad(name"New Toad"

現在,你擁有了以下簡練的方法。其中,我提供了幾點補充,以進一步解釋代碼的作用:

  1. func turnFamiliarIntoToad() throws -> Toad { 
  2.  
  3. // When have you ever seen a Witch perform a spell without her magical hat on ? :] 
  4.  
  5. guard let hat = hat where hat.isMagical else { 
  6.  
  7. throw ChangoSpellError.HatMissingOrNotMagical 
  8.  
  9.  
  10. // Check if witch has a familiar 
  11.  
  12. guard let familiar = familiar else { 
  13.  
  14. throw ChangoSpellError.NoFamiliar 
  15.  
  16.  
  17. // Check if familiar is already a toad - if so, why are you casting the spell? 
  18.  
  19. if familiar is Toad { 
  20.  
  21. throw ChangoSpellError.FamiliarAlreadyAToad 
  22.  
  23.  
  24. guard hasSpellOfType(.PrestoChango) else { 
  25.  
  26. throw ChangoSpellError.SpellNotKnownToWitch 
  27.  
  28.  
  29. // Check if the familiar has a name 
  30.  
  31. guard let name = familiar.name else { 
  32.  
  33. let reason = "Familiar doesn’t have a name." 
  34.  
  35. throw ChangoSpellError.SpellFailed(reason: reason) 
  36.  
  37.  
  38. // It all checks outReturn a toad with the same name as the witch's familiar 
  39.  
  40. return Toad(namename
  41.  

以前,從turnFamiliarIntoToad()方法中返回一個可選項僅表明了“施加這個魔法時出現了某種錯誤”。但,像這樣使用自定義的錯誤,你可以更清楚地表示錯誤狀態,從而對其做出相應的反應。

其他適合定制錯誤的地方

現在,既然建立了方法可以拋出自定義Swift錯誤,你就需要進一步處理這些錯誤。這樣做的標準機制稱為do-catch語句,這類似于在其他如Java語言中使用的try-catch機制。

現在,請將下面的代碼添加到你的工程文件的***:

  1. func exampleOne() { 
  2.  
  3. print("") // Add an empty line in the debug area 
  4.  
  5. // 1 
  6.  
  7. let salem = Cat(name"Salem Saberhagen"
  8.  
  9. salem.speak() 
  10.  
  11. // 2 
  12.  
  13. let witchOne = Witch(name"Sabrina", familiar: salem) 
  14.  
  15. do { 
  16.  
  17. // 3 
  18.  
  19. try witchOne.turnFamiliarIntoToad() 
  20.  
  21.  
  22. // 4 
  23.  
  24. catch let error as ChangoSpellError { 
  25.  
  26. handleSpellError(error) 
  27.  
  28.  
  29. // 5 
  30.  
  31. catch { 
  32.  
  33. print("Something went wrong, are you feeling OK?"
  34.  
  35.  

以下是該函數所實現的任務:

1. 創建這個女巫的寵物,它是一只叫Salem的貓。

2. 創建女巫,名字叫Sabrina。

3. 嘗試把這只貓變成一只癩蛤蟆。

4. 捕獲一個ChangoSpellError錯誤,并適當地處理錯誤。

5. ***,捕捉所有其他錯誤并打印出一條友好的信息。

添加上述內容后,你會看到一個編譯器錯誤。現在,我們著手解決這個問題。

handleSpellError()方法尚未定義,因此,把下列代碼添加到前面exampleOne()函數定義的上面:

  1. func handleSpellError(error: ChangoSpellError) { 
  2.  
  3. let prefix = "Spell Failed." 
  4.  
  5. switch error { 
  6.  
  7. case .HatMissingOrNotMagical: 
  8.  
  9. print("\(prefix) Did you forget your hat, or does it need its batteries charged?"
  10.  
  11. case .FamiliarAlreadyAToad: 
  12.  
  13. print("\(prefix) Why are you trying to change a Toad into a Toad?"
  14.  
  15. default
  16.  
  17. print(prefix) 
  18.  
  19.  

***,把以下內容添加到文件的底部并運行工程代碼:

  1. exampleOne() 

你會看到調試控制臺輸出顯示有關內容:

捕獲錯誤

下面給出在上面的代碼片段中使用的每一個Swift 2錯誤處理技術的簡短概括。

catch子句

你可以在Swift中使用模式匹配來處理特定錯誤或把幾種錯誤類型放在一起處理。

上面的代碼中向你演示了捕獲錯誤的幾種用法:一個是捕獲特定的ChangoSpell錯誤,一個是一起處理剩余錯誤的情況。

try子句

你可以使用try子句并結合do-catch子句來清楚表明哪些行或代碼段可能拋出錯誤。

你可以通過幾種不同的方式來使用try命令,上面使用過的是下面之一:

try——清楚和直接的do-catch語句中的標準用法,這是上面代碼中使用的方式。

try?——本質上是通過忽視錯誤的方式來處理錯誤;如果拋出一個錯誤,語句的結果將為nil。

try!——該子句強調一種期望結果:理論上,一個語句能夠拋出一個錯誤;但實際上,這種錯誤條件永遠不會發生。try!子句可用于像加載文件這樣的編程代碼中,這種情況下你有把握確保某些所需的媒體存在。應小心使用這個子句。

現在,讓我們具體地了解try?子句的用法。你可以把下列代碼剪切并粘貼到你上面文件的底部:

  1. func exampleTwo() { 
  2.  
  3. print("") // Add an empty line in the debug area 
  4.  
  5. let toad = Toad(name"Mr. Toad"
  6.  
  7. toad.speak() 
  8.  
  9. let hat = Hat() 
  10.  
  11. let witchTwo = Witch(name"Elphaba", familiar: toad, hat: hat) 
  12.  
  13. let newToad = try? witchTwo.turnFamiliarIntoToad() 
  14.  
  15. if newToad != nil { // Same logic as: if let _ = newToad 
  16.  
  17. print("Successfully changed familiar into toad."
  18.  
  19.  
  20. else { 
  21.  
  22. print("Spell failed."
  23.  
  24.  

請注意上面代碼中exampleOne的不同之處。在這里,你不必關心特定錯誤的輸出問題,但仍然要捕捉發生錯誤的事實。這里并沒有創建蟾蜍寵物;所以,newToad的值為nil。

傳播錯誤

throws

如果一個函數或方法拋出錯誤,在Swift中需要使用throws關鍵字。拋出的錯誤會沿調用堆棧向上自動傳播,但人們普遍認為讓錯誤從其發生源地傳播太遠是一個不好的做法。在整個代碼庫中增加錯誤可能性的重大傳播可能會躲過恰當的錯誤處理機會;為此,借助于throws關鍵字可以確保傳播能夠在代碼中記錄在案,并且對編程人員也很容易了解這一點。

rethrows

目前為止,你所看到的所有示例都使用了throws,但怎么使用rethrows呢?

rethrows告訴編譯器僅當函數參數拋出錯誤時這個函數才拋出錯誤。下面是一個最直接的例子(無需將它添加到前面的文件中):

  1. func doSomethingMagical(magicalOperation: () throws -> MagicalResult) rethrows -> MagicalResult { 
  2.  
  3. return try magicalOperation() 
  4.  

在這里,doSomethingMagical(_:)方法僅當提供給函數的magicalOperation參數拋出錯誤時才拋出錯誤。如果成功了,它返回一個MagicalResult值。

操縱錯誤處理行為

defer

雖然自動傳播在大多數情況下工作良好,但也有些情況下,當錯誤在調用堆棧中向上傳播時你可能要進一步控制你的應用程序的行為。

Defer語句提供了一種機制,每當退出當前范圍允許程序執行“清理”工作,如方法或函數返回時。它用于管理需要清理的資源——無論動作是否成功。因此,在錯誤處理上下文中尤為有用。

【譯者注】建議你結合C++/Java等語言中的finally子句加以理解。

為了了解defer的使用,請將下面的方法添加到Witch結構的***:

  1. func speak() { 
  2.  
  3. defer { 
  4.  
  5. print("*cackles*"
  6.  
  7.  
  8. print("Hello my pretties."
  9.  

然后,將下面的代碼添加到前面文件的底部:

  1. func exampleThree() { 
  2.  
  3. print("") // Add an empty line in the debug area 
  4.  
  5. let witchThree = Witch(name"Hermione", familiar: nil, hat: nil) 
  6.  
  7. witchThree.speak() 
  8.  
  9.  
  10. exampleThree() 

在調試控制臺中,您應該看到女巫在說完所有話后發出咯咯的笑聲。

有趣的是,defer語句是以其編程時順序的相反的順序執行的。

現在,我們把另一個defer添加到speak()語句,以便女巫可以咯咯地發笑。然后,女巫在說完所有話后發出咯咯的笑聲:

  1. func speak() { 
  2.  
  3. defer { 
  4.  
  5. print("*cackles*"
  6.  
  7.  
  8. defer { 
  9.  
  10. print("*screeches*"
  11.  
  12.  
  13. print("Hello my pretties."
  14.  

你注意到調試控制臺中的輸出順序了嗎?這正是defer語句的能力!

與錯誤有關的更有趣的事情

本文中提供的上述Swift語句使其與很多其他受歡迎的語言保持了一致,從而把Swift從Objective-C基于NSError基礎的錯誤處理方法中分離出來。而大多數情況下的Objective-C錯誤都是直譯式的,編譯器中的靜態分析器能夠很好地幫助你確定你需要哪些錯誤及何時需要捕獲錯誤。

雖然do-catch相關支持語句在其他語言中也有很大的開銷;但是,在Swift語言中,它們基本上像任何其他語句一樣處理。這將確保它們的有效性和高效率。

但是,不要因為你可以創建自定義錯誤并拋出錯誤并隨意地使用。這方面,建議你針對你開發的工程先制定一些準則:何時需要拋出和捕獲錯誤。對此,我提出下列建議:

確保錯誤類型在您的整個代碼庫中被清楚地命名。

當單個錯誤狀態時盡量使用可選值(Optionals)。

當存在超過一個錯誤狀態時使用自定義錯誤處理技術。

不允許錯誤從其源地傳播得太遠。

未來的Swift錯誤處理

在各種Swift論壇中經常討論幾種高級錯誤處理想法。其中,談論最多的概念之一是非類型化傳播的問題。

“......我們相信我們可以擴展我們當前的模型以支持非類型化傳播的普遍錯誤。這項工作怎樣才能做得很好——特別是在不完全犧牲代碼大小和性能的情況下,將引發大量深度研究。可以預測,在Swift 2.0中實現這一方法是沒有問題的。”(來自《Swift 2.x Error Handling》)

不論你是否在享用Swift 3中的主流錯誤處理思想,是否對于今天存在的東西滿意,令人高興的是,隨著語言技術的繼續發展,整潔的錯誤處理技術正在各地積極討論中并不斷改進。

小結

您可以下載本教程已完成的游樂場示例工程進一步研究討論,地址是https://cdn2.raywenderlich.com/wp-content/uploads/2016/04/Magical-Error-Handling-in-Swift.zip

如果你渴望看到有關Swift 3的新進展,我推薦你參閱《Swift Language Proposals》(https://github.com/apple/swift/tree/master/docs/proposals)。

希望到目前為止,你已經真正沉迷于Swift中的錯誤處理技術。

責任編輯:趙立京 來源: 51CTO
相關推薦

2023-10-26 12:05:14

Golang開發

2024-03-27 08:18:02

Spring映射HTML

2011-07-06 15:04:41

ASP

2021-04-14 07:08:14

Nodejs錯誤處理

2022-09-05 08:55:15

Go2提案語法

2022-11-16 08:41:43

2014-11-17 10:05:12

Go語言

2010-06-01 16:14:04

2009-08-05 16:04:50

2023-10-28 16:30:19

Golang開發

2021-04-29 09:02:44

語言Go 處理

2017-03-08 08:57:04

JavaScript錯誤堆棧

2017-04-06 14:40:29

JavaScript錯誤處理堆棧追蹤

2011-05-25 10:26:42

ora-02069錯誤

2015-08-19 14:11:56

SQL Server錯誤處理

2023-12-26 22:05:53

并發代碼goroutines

2010-09-17 10:04:36

2023-11-08 15:04:55

事務GORM

2009-06-19 16:20:14

ASP.NET錯誤處理

2023-10-08 20:31:18

React
點贊
收藏

51CTO技術棧公眾號

天天综合天天综合色| 一本色道久久综合亚洲精品不| 亚洲福利一区二区| 91高清免费在线观看| 婷婷无套内射影院| 中文字幕亚洲乱码熟女1区2区| 国产一区二区三区黄网站| 国产日韩综合av| 久久精品视频网站| 亚洲人成无码网站久久99热国产| 国产熟女精品视频| 日韩激情在线| 欧美性淫爽ww久久久久无| 成人网在线免费看| av2014天堂网| 免费av在线播放| 亚洲久久一区| 亚洲精品久久久久中文字幕欢迎你 | 手机成人av在线| 在线视频你懂得| 成人av激情人伦小说| 中文字幕精品三区| 国产精品自产拍在线观| 可以免费看av的网址| 懂色aⅴ精品一区二区三区| 中文一区在线播放| 欧美一区二区三区免费视| 三年中文在线观看免费大全中国| 欧美精品少妇| 亚洲视频狠狠| 亚洲精品日韩丝袜精品| 日本精品一区二区三区四区| 久草在线青青草| 麻豆国产一区二区| 萌白酱国产一区二区| 欧美日韩一区二区区| 97人人在线| 国产精品一区一区三区| 中文字幕欧美日韩va免费视频| 中文字幕亚洲影院| 欧美男男video| 国产精品自拍毛片| 午夜精品一区二区三区视频免费看| 九九热免费在线观看| 黄色av网站在线| 麻豆精品网站| 久久久精品亚洲| 成人日韩在线视频| porn视频在线观看| 国产成人免费视频| 精品国产一区二区三区久久狼黑人| 可以看的av网址| a毛片在线看免费观看| 久久99国产精品久久99果冻传媒| 久久久久久久999| 国产一二三四五区| 亚洲成人偷拍| 亚洲一区二区高清| 99在线视频免费观看| 成年人av电影| 国产精品日韩精品中文字幕| 日韩一区二区视频| 一区二区免费电影| 无码精品黑人一区二区三区| 久久国产精品99久久人人澡| 97av在线视频免费播放| 超碰97人人干| 99久久免费精品国产72精品九九| 欧美综合亚洲图片综合区| 国产亚洲精品久久久久久久| 亚洲大尺度视频| 免费看黄色91| 7777免费精品视频| 少妇久久久久久被弄高潮| 一本一道久久a久久| 欧美性淫爽ww久久久久无| 欧美在线视频网| 亚洲综合欧美综合| 成人中文字幕视频| 欧美卡1卡2卡| 欧美日韩dvd| 国产精品四虎| 国产在线视频一区二区| 日韩美女在线观看| 久久久精品视频免费| 婷婷综合一区| 欧美日韩精品三区| 无码aⅴ精品一区二区三区浪潮| av网站在线免费| 国产精品美女视频| 日本视频精品一区| 污视频在线免费| 风间由美一区二区三区在线观看| 欧美亚洲伦理www| 日韩xxxxxxxxx| 欧美日韩综合| 国产一区二区三区18| 欧美日韩久久婷婷| 日韩理论视频| 国产精品久久久久婷婷| 日本视频一区二区在线观看| 免费a级毛片在线观看| 99在线精品一区二区三区| 国产极品精品在线观看| 国产99免费视频| 女同性一区二区三区人了人一| 日韩精品免费在线播放| 玖玖爱在线精品视频| 国偷自产视频一区二区久| 精品剧情在线观看| 中国特级黄色片| 爱爱精品视频| 色哟哟欧美精品| 久久这里只有精品8| 国内在线免费高清视频| 国产寡妇亲子伦一区二区| 亚洲aaa激情| 黄色av一区二区| 伊人精品成人久久综合软件| 国外成人在线直播| 日本精品在线免费观看| 91精品啪在线观看国产18| 亚洲精品视频二区| 一级黄色电影片| 欧美三级自拍| 亚洲性xxxx| 搡老熟女老女人一区二区| 亚洲人成网77777色在线播放 | 黑人巨大猛交丰满少妇| 日韩不卡视频在线观看| 欧美精品国产精品| 亚洲色图久久久| 精品精品视频| 亚洲国产一区自拍| 熟女高潮一区二区三区| 日韩伦理一区| 色综合视频网站| 五月天婷婷色综合| 五月天久久网站| 中文字幕亚洲欧美| 国产一级久久久| 老鸭窝亚洲一区二区三区| 韩国精品久久久999| 无码免费一区二区三区| 99综合在线| 久久久久久国产三级电影| aaaaaa毛片| 国产在线播放一区| 久久久婷婷一区二区三区不卡| gogogo高清在线观看免费完整版| 久久蜜桃av一区精品变态类天堂| 一区二区三区av在线| 国产又色又爽又黄刺激在线视频| 日本福利一区二区| 日本黄色www| 精品理论电影在线| 欧美黑人极品猛少妇色xxxxx| 无码免费一区二区三区| 高清成人在线观看| 国产综合动作在线观看| 香蕉视频在线看| 亚洲丝袜另类动漫二区| 一区二区三区四区久久| 自拍在线观看| 欧美体内she精视频| 久久撸在线视频| 日日天天久久| 欧美情侣性视频| 国产大片中文字幕| 亚洲免费影视| 国产精品视频26uuu| 天堂在线资源8| 亚洲人精品午夜| 青青草精品视频在线观看| 国产一区二区三区亚洲| 久久亚洲春色中文字幕| 精品少妇久久久| 久久99精品国产麻豆婷婷洗澡| 99re国产在线播放| 最近高清中文在线字幕在线观看| 日韩欧美在线中文字幕| 制服.丝袜.亚洲.中文.综合懂| 成人综合专区| 欧美日本在线视频中文字字幕| 日韩精品一区二区不卡| 国产精品夜夜爽| 欧美激情第一页在线观看| 91福利在线免费| 欧美午夜精品免费| 亚洲熟女乱综合一区二区| 五月激情久久久| 国产精品欧美日韩一区二区| 韩国三级在线观看久| 色网站国产精品| 一区二区三区少妇| 亚洲经典在线看| 国产精品毛片va一区二区三区| 欧美精品hd| 欧美视频一区二区三区…| xx欧美撒尿嘘撒尿xx| 国产一区二区三区电影在线观看 | 国产成人在线视频观看| 波多野结衣91| 一本一生久久a久久精品综合蜜| 美女网站视频在线| 日韩精品一区二区三区在线观看| 中文字幕在线观看成人| 国产成人99久久亚洲综合精品| 欧美精品尤物在线| 日本成人三级电影| 精品国产一区二区三区忘忧草| 久久亚洲精品大全| av不卡在线播放| 公共露出暴露狂另类av| 美脚恋feet久草欧美| 欧美大胆人体bbbb| 日韩乱码一区二区| 久久久久久亚洲综合| 免费看污污网站| 欧美系列电影免费观看| 538国产精品一区二区免费视频| 四虎影视2018在线播放alocalhost| 亚洲成人动漫精品| 草草影院第一页| 另类专区欧美蜜桃臀第一页| 欧美xxxx黑人又粗又长精品| 向日葵视频成人app网址| 亚洲国产另类久久精品| 无码人妻久久一区二区三区 | 精品电影一区二区| 国产免费av一区二区| 国产午夜亚洲精品午夜鲁丝片 | 亚洲一区二区久久| 97超视频在线观看| 国产精品热久久久久夜色精品三区| 日韩欧美理论片| 婷婷综合在线| 亚洲一区美女视频在线观看免费| 欧美黑人xx片| 亚洲精品永久免费| 97人妻人人澡人人爽人人精品 | 最新中文字幕一区| 国产精品―色哟哟| 第一页在线视频| 久久中文精品| 在线观看17c| 综合中文字幕| 国产精品一区二区三区成人| 欧美24videosex性欧美| 亚洲新声在线观看| 伊人久久一区二区| 亚洲国产一二三| 黄色片在线观看免费| 毛片一区二区三区| 国产视频一视频二| 亚瑟一区二区三区四区| 国产成人+综合亚洲+天堂| 在线中文字幕-区二区三区四区| 亚洲人成伊人成综合网久久久 | 日韩精品在线免费看| 99久久久精品免费观看国产蜜| 日韩欧美一区二| 欧美成人有码| 亚洲欧美日产图| 色先锋久久影院av| 国产成人精品视| 日本美女高清在线观看免费| 日韩一区二区三区观看| 精品一区二区三区人妻| 亚洲视频资源在线| 少妇无套高潮一二三区| 99久久久精品免费观看国产蜜| 婷婷中文字幕在线观看| 免费久久99精品国产| 狠狠精品干练久久久无码中文字幕| 狠狠一区二区三区| 97人人香蕉| 性感美女一区二区在线观看| 视频在线观看99| 国产高清在线看| 精品伊人久久97| 中文字幕在线播放不卡| 亚洲一线二线三线视频| 五月婷婷综合在线观看| 麻豆成人久久精品二区三区红 | 香蕉视频亚洲一级| 国外成人在线播放| 在线观看h片| 亚洲美女激情视频| 香蕉久久一区二区三区| 精品99999| 欧美特级特黄aaaaaa在线看| 欧美午夜精品久久久久久超碰| 日韩不卡视频在线| 亚洲视频一区二区在线| 国产偷人妻精品一区| 99热这里都是精品| 中文文字幕文字幕高清| 97se亚洲国产综合自在线不卡 | 欧美激情一级精品国产| 在线观看午夜av| 久久99精品视频一区97| 成人精品一区二区三区免费| 亚洲成人网久久久| 在线观看日韩一区二区| 欧美人妇做爰xxxⅹ性高电影| 中文字幕 亚洲视频| 精品国产91乱高清在线观看 | 欧美巨大另类极品videosbest| 探花国产精品一区二区| 欧美日韩一区二区三区四区五区| 韩国av免费观看| 亚洲精品中文字幕在线观看| 久久久久久久久久久久久女过产乱| 亚洲精品视频在线| 久久久久99精品成人| 2017欧美狠狠色| 丁香激情五月少妇| 亚洲欧洲成人精品av97| 成年人在线免费看片| 国产精品福利一区| 欧美又粗又大又长| 亚洲欧洲av在线| 少妇影院在线观看| 午夜精品一区二区三区电影天堂 | 欧美大胆的人体xxxx| 97超碰蝌蚪网人人做人人爽 | 欧美网站一区二区| 国产嫩bbwbbw高潮| 精品免费在线观看| 亚洲精品一区二三区| 色婷婷综合五月| 久久免费激情视频| 91激情在线视频| 亚洲欧美另类在线视频| 欧美高清激情brazzers| 亚洲视频一区在线播放| 欧美zozozo| 国产精品秘入口| 国产香蕉97碰碰久久人人| 黑人与亚洲人色ⅹvideos| 亚洲视频在线免费观看| 亚州av在线播放| 久久久精品影院| 黄页视频在线播放| 91精品国产色综合| 中文字幕成人| 欧美日韩亚洲一区二区三区在线观看| 日韩mv欧美mv国产网站| 久久久久网址| 欧美日韩一区二区综合| 亚洲乱码日产精品bd在线观看| 欧美精品首页| 欧美三级理论片| 老司机免费视频一区二区三区| 特级丰满少妇一级| 激情文学综合丁香| 欧美视频亚洲图片| 国产网站一区二区| 久久久久亚洲AV成人| 色哟哟一区二区在线观看| 成 人片 黄 色 大 片| 亚洲国产精久久久久久 | 手机看片一级片| 99国产精品国产精品久久| 久久亚洲AV成人无码国产野外| 亚洲一区二区在线免费观看视频 | 清纯唯美一区二区三区| 不卡日本视频| 丝袜老师办公室里做好紧好爽| 国产精品一级二级三级| 天天躁日日躁狠狠躁免费麻豆| **欧美大码日韩| 这里只有久久精品视频| 国产偷国产偷亚洲清高网站| 在线观看完整版免费| 日韩美女在线播放| 亚洲超碰在线观看| 青青在线免费视频| 老司机精品视频一区二区三区| 黄色片网站免费| 一区二区高清视频在线观看| 欧美日韩乱国产| 欧美一区二区三区四区高清| 污视频在线免费| 78色国产精品| 99tv成人影院| 中文字幕色一区二区| 欧美aaa在线| 中国免费黄色片| 亚洲国产综合人成综合网站| 亚洲欧美强伦一区二区| 亚洲午夜性刺激影院| 黄色小说在线播放| 国产精品久久久久久久久男| 北条麻妃一区二区三区在线| 精品成在人线av无码免费看| 国产成人av影院| 国产午夜精品无码| 亚洲成色www8888|