窺探 Swift 編程之錯誤處理與異常拋出

来源:http://www.cnblogs.com/8hao/archive/2016/03/01/5230686.html
-Advertisement-
Play Games

在Swift 2.0版本中,Swift語言對其錯誤處理進行了新的設計,當然了,重新設計後的結果使得該錯誤處理系統用起來更爽。今天博客的主題就是系統的搞一下Swift中的錯誤處理,以及看一下Swift中是如何拋出異常的。在編譯型語言中,錯誤一般分為編譯錯誤和運行時錯誤。我們平時在代碼中處理的錯誤為運行


在Swift 2.0版本中,Swift語言對其錯誤處理進行了新的設計,當然了,重新設計後的結果使得該錯誤處理系統用起來更爽。今天博客的主題就是系統的搞一下Swift中的錯誤處理,以及看一下Swift中是如何拋出異常的。在編譯型語言中,錯誤一般分為編譯錯誤和運行時錯誤。我們平時在代碼中處理的錯誤為運行時錯誤,我們對異常進行處理的操作的目的是為了防止程式出現錯誤而導致其他的副作用,比如用戶數據未保存等等。

在今天的博客中,先給出主動產生異常的幾種情況,然後再給出如何處理被動異常。

一、主動退出程式的幾種情況

在Objective-C中,在單元測試時我們會使用斷言,斷言中條件滿足時會產生異常,並列印出相應的斷言錯誤,在Swift中也有幾種產生異常的語法。在本篇博客的第一部分就給出這幾種方法。

1.Fatal Errors(致命的錯誤)

使用fatalError()函數可以立即終止你的應用程式,在fatalError()中可以給出終止信息。使用fatalError()函數,會毫無條件的終止你的應用程式,用起來也是比較簡單的,就是一個函數的調用。下方這個Demo一目瞭然呢,在此就不做過多贅述了。

 

2. Assertions(斷言)

在單元測試中是少不了斷言的,Swift中的斷言和Objective-C的區別不是太大,使用方法也是大同小異。下方就是斷言的兩種方法,由代碼提示可知,在斷言中的提示條件是可選的。斷言會在Debug模式下起作用,但是在Release版本中就會被忽略。

 

在assert()函數中, 第一個參數是Bool類型,第二個參數是輸出的信息。當條件為true時,斷言不執行,相應的斷言信息不列印。當條件為false時,斷言執行,並且列印相應的斷言信息。

 

assertionFailure()函數只有一個Message參數,並且該參數也是可以省略的,assertionFailure()沒有條件。如下所示:

 

3. 先決條件(Preconditions)

Preconditions的用法和斷言一樣,不過有一點需要主要,Preconditions在debug和release模式下都會被執行,除非使用–Ounchecked進行編譯。下方截圖是代碼提示給出的Preconditions函數的提示,如下所示:

關於Preconditions的具體用法請參照斷言,和斷言用法一樣,在此就不做過多的贅述了。

 

二.Swift中的錯誤處理

在Objective-C中,如果你處理過錯誤的話,那麼你將會對NSError很熟悉。在Swift中,如果你要定義你自己的錯誤類型,你只需要實現ErrorType協議即可。聲明完錯誤類型後,就可以在處理錯誤拋出異常時使用自定義的錯誤類型了。下方將會一步步帶你走完Swift中的錯誤處理的路程。

1.使用枚舉創建錯誤類型

(1).遵循ErrorType協議,自定義錯誤類型。下方定義了一個錯誤類型枚舉,該枚舉遵循了ErrorType協議,在接下來的代碼中我們將會使用這個MyCustomErrorType枚舉,錯誤枚舉的實現如下所示:

   
1 2 3 4 5 6 //定義錯誤類型 enum MyCustomErrorType: ErrorType {      case ErrorReason1      case ErrorReason2      case ErrorReason3 }

(2).在我們的函數定義時可以使用throws關鍵字,以及在函數中使用throw關鍵字對錯誤進行拋出,拋出的錯誤類型就可以使用上面我們自己定義的錯誤類型。下方函數就是一個可以拋出錯誤的函數,拋出的錯誤就是我們在上面枚舉中所定義的類型。具體代碼如下所示:

   
1 2 3 4 5 6 7 8 func myThrowFunc1() throws {        let test:Int? = nil        guard test != nil else {          throw MyCustomErrorType.ErrorReason1      } }

(3).上面函數的功能是對錯誤進行拋出,接下來就該使用do-catch來處理拋出的錯誤。使用try對錯誤進行捕捉,使用do-catch對錯誤進行處理。具體處理方式如下所示。在下方錯誤處理中類似於switch-case語句,catch後邊可以枚舉匹配錯誤類型,具體如下所示:    

 

(4)在枚舉實現錯誤類型中我們可以通過值綁定的形式為錯誤添加錯誤代碼和錯誤原因。在聲明枚舉時,我們使用了枚舉元素值綁定的特性(關於枚舉使用的更多細節請參考之前的博客《窺探Swift之別樣的枚舉類型》)。在聲明枚舉成員ErrorState時,我們為其綁定了兩個變數,一個是錯誤代碼errorCode, 另一個是錯誤原因errorReason。這兩者可以在拋出錯誤時為其傳入相應的值,如下方代碼片段中的throwError函數所示,在拋出錯誤是為errorCode指定的錯誤代碼為404,為errorReason指定的錯誤原因是“not found”。

最後就是使用do-catch處理異常了,在catch中對綁定的錯誤代碼和錯誤原因進行了獲取,並且通過where子句進行了錯誤代碼的篩選。此處catch的用法與switch-case中獲取枚舉綁定值的用法是一樣的,所以在此就不做過多的贅述。具體實現方式如下代碼所示:

 

2.使用結構體為錯誤處理添加Reason

在上面的內容中,使用枚舉遵循ErrorType協議的方式定義了特定的錯誤類型。接下來我們將使用結構體來遵循ErrorType協議,為錯誤類型添加錯誤原因。也就是說,我們可以在拋出錯誤時,給自定義錯誤類型提供錯誤原因。該功能在開發中是非常常用的,而且用起來也是非常爽的。接下來就看一下如何為我們的錯誤類型添加錯誤原因。

(1)使用結構體創建錯誤類型,下方名為MyErrorType的結構體遵循了ErrorType協議,並且在MyErrorType結構體中,聲明瞭一個reason常量,該reason常量中存儲的就是錯誤原因,具體實現方式如下:

   
1 2 3 struct MyErrorType: ErrorType {      let reason : String }

(2)上面定義完錯誤類型結構體後,在錯誤拋出中就可以使用了。在錯誤拋出時,可以傳入一個錯誤原因,具體代碼如下所示:

   
1 2 3 4 5 6 7 8 func myThrowFunc2() throws {        let test:Int? = nil        guard test != nil else {          throw MyErrorType(reason: "我是詳細的錯誤原因,存儲在error中")      } }

(3)最後要對拋出的錯誤進行do-catch處理,在處理時,可以對錯誤原因進行列印,錯誤原因存儲在error中,具體操作和列印結果如下所示:

由上面的輸出結果可知,error是我們自定義的MyErrorType類型,我們可以使用下麵的代碼來代替catch中的print語句,如下所示:

 

上面的做法似乎有些麻煩,還有一種簡化輸出的方法,就是在上述結構體中實現CustomDebugStringConvertible協議,對描述信息進行一個重寫,就可以在列印error時,只列印錯誤信息,下方是重寫後的結構體。   

   
1 2 3 4 5 6 1 struct MyErrorType: ErrorType,CustomDebugStringConvertible { 2     let reason : String 3     var debugDescription: String { 4         return "錯誤類型-----(self.dynamicType): (reason)" 5     } 6 }

修改後,輸出結果如下,直接列印error輸出的就是錯誤信息,而不是MyErrorType類型。

 

3.使String類型遵循ErrorType協議,直接使用String提供錯誤原因

在“2”中,我們使用了結構體遵循ErrorType協議的形式,來為錯誤提供錯誤信息的。在接下來的部分,我們將通過更為簡單的方式為拋出的錯誤提供錯誤信息。這種方式更為簡單,也易於理解,具體方式如下方代碼所示:

 

三、在錯誤處理中使用內置關鍵字

1.初探這些內置關鍵字

在Swift中提供了一些內置關鍵字(__FILE__, __FUNCTION__, __LINE__等)來獲取上下文信息,在本篇博客的第三部分,將會給出如何在我們的錯誤處理中使用這些內置關鍵字。下方就是這些內置關鍵字的作用,如下所示:

上面說是內置關鍵字,其實就是存儲代碼上下文的巨集定義,上方代碼段簡單的給出了這些內置關鍵字的作用與用法,在接下來將在ErrorType中使用這些內置關鍵字,讓我們的錯誤信息更加豐富多彩。

 

2.在ErrorType中使用上述內置關鍵字

如果想在ErrorType中使用這些上下文內置關鍵字,我們只需要對ErrorType進行擴展,使其在ErrorType提供錯誤信息時給出出錯的上下文信息。當然,這實現起來比較簡單,就是在ErrorType中添加了一個擴展方法contextString()。該方法的作用就是提供錯誤的上下文信息,也就是在出錯的地方,調用contextString()方法生成上下文描述信息即可。對ErrorType協議的具體延展實現如下代碼段所示.

在下方代碼片段中,我們對ErrorType進行了擴展,為ErrorType添加了contextString的函數實現。contextString()函數有三個預設參數,分別是file–當前文件名,function–當前出錯的函數名,line–當前拋出異常的行數。上述三個參數都有參數預設值,分別對應著__FILE__, __FUNCTION__, __LINE__。該擴展函數的返回值為這三個參數組成從字元串信息。具體實現如下所示:

 

3.使用擴展的contextString方法

上面我們使用結構體實現ErrorType協議的形式,為錯誤類型添加錯誤原因。接下來我們將在添加reason的同時,使用contextString()函數添加描述信息。下方CustomErrorType結構體遵循了ErrorType協議,其中添加了一個reason常量來存儲錯誤原因,一個context常量來存儲上下文信息,並且為該結構體添加了一個構造函數,在構造函數中初始化和reason常量。具體實現如下所示:

 

4. 拋出並捕獲異常

在下方代碼中函數throwError()拋出了異常,該拋出的錯誤類型是CustomErrorType。在創建CustomErrorType類型實例,也就是err變數時,我們指定了錯誤原因,也就是為reason賦了一個值。在創建完err實例後,我們又調用延展contextString()函數獲取異常的上下文信息,並把返回的內容存儲在err實例的context屬性中。最後使用throw關鍵字拋出err實例,如下方第一部分代碼所示。

在創建拋出異常的函數後,我們需要對拋出的異常進行捕獲。也就是使用try對異常進行捕獲,使用do-catch對異常進行處理,具體操作如下方第二段代碼所示。

 

5. 分析列印結果

經過上述步驟如果你在Playground中進行試驗的,那麼在控制臺上你將會看到如下信息。從列印出的信息我們可以看到,信息包括reason:錯誤原因,和context:異常上下文。在下方的輸出結果中,文件名我們可以看到是這並不是確切的文件名,因為我們是在Playground中使用的,並且不是確切的Swift源文件,所以獲取不到確切的文件名。

為了觀察確切的文件名,我們需要在確切的Swift源文件中拋出上述異常。在特定Swift源文件中,我們會看到下方的輸出結果。從下方的輸出日誌中,我們可以清楚的看到文件名是一個詳細的文件路徑。如下所示:

 

問啊-一鍵呼叫程式員答題神器,牛人一對一服務,開發者編程必備官方網站:www.wenaaa.com

QQ群290551701 聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 應用背景:在頁面中有兩個列表框,需要把其中一個列表框的元素移動到另一個列表框 。 實現的基本思想: (1)編寫init方法對兩個列表框進行初始化; (2)為body添加onload事件調用init方法; (3)編寫move(s1,s2)把s1中選中的選項移到s2; (4)編寫moveAll(s1,s
  • 先是HTML 一個父div包含四個絕對定位的div <div class='container container--realistic'> <div class='cube cube--ani'> <div class='face'>1</div> <div class='face'>2</div
  • 1.常用的方式是:將一張圖片設置為背景,然後在裡面加文字,你加入的圖片代碼是: <img src="img.jpg" width='100px" height="50px"> 改為 <div style="background:url('img.jpg') no-repeat;width:100px
  • 1.9.1以後的版本,好像不支持 jq 的 toggle function的用法啦。
  • JS代碼 //圖像載入出錯時的處理 function errorImg(img) { img.src = "預設圖片.jpg"; img.onerror = null; } HTML代碼 <img width="32" height="32" src="1.jpg" onerror="errorIm
  • 有關name: 一、頁面關鍵字 網站關鍵字:用戶通過搜索引擎能搜到該網站的辭彙。最好控制在10個以內。 基本語法: <meta name="keywords" content="具體的關鍵字"> 示例代碼: 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta ch
  • 時間就是金錢。編碼效率的提升意味著更多的收入。可是當我們的開發技巧已經到達一定高度時,如何讓開發效率更上一層樓呢?答案就是使用開發工具!在這篇文章中,我會向你介紹一些幫助我提升編碼速度和工作效率的工具。 Xcode插件 幾乎所有開發者都知道Alcatraz是一個開源的包管理工具,可以讓我們更輕鬆地管
  • 前言 iOS8之後系統自帶使用AVPlayerViewController播放視頻 AVPlayerViewController AVPlayerViewController和導航控制器差不多,需要將它添加在一個視圖控制器上,將它的視圖添加視圖上 1.導入頭文件 #import <AVKit/AVK
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...