Swift Error 的介紹和使用

同步我的掘金MeR

??鶸學(xué)python看到錯誤處理這一章的時候,就想對比著swift來研究一下。
??本文前面是Error蘋果文檔的介紹,然后對Alamofire中的使用作簡單介紹作為實踐;后面還有關(guān)于fatalError和高級語言錯誤處理機制的理解


Error蘋果文檔

Swift中的Error長這個樣子

public protocol Error {
}

extension Error {
}

extension Error where Self.RawValue : SignedInteger {
}

extension Error where Self.RawValue : UnsignedInteger {
}

蘋果文檔對Error的介紹

A type representing an error value that can be thrown. Any type that declares conformance to the Error protocol can be used to represent an error in Swift’s error handling system. Because the Error protocol has no requirements of its own, you can declare conformance on any custom type you create.

??從介紹上可以看出遵守這個Error協(xié)議,就可以將錯誤拋出和捕獲,而且任何自定義的類型都可以遵守此Error協(xié)議。
??文檔中舉了兩個例子,第一個是自定義枚舉遵守Error來對Error進行分類,下面我們著重看下蘋果爸爸給出的第二個例子:用一個遵守Error協(xié)議的結(jié)構(gòu)體來獲取更多的錯誤信息。

struct XMLParsingError: Error {
    enum ErrorKind {
        case invalidCharacter
        case mismatchedTag
        case internalError
    }

    let line: Int
    let column: Int
    let kind: ErrorKind
}

func parse(_ source: String) throws -> XMLDoc {
    // ...
    throw XMLParsingError(line: 19, column: 5, kind: .mismatchedTag)
    // ...
}

例子中創(chuàng)建了一個遵守Error協(xié)議的結(jié)構(gòu)體 XMLParsingError,帶有三個屬性來記錄解析XML文件時出錯的錯誤類型和行列信息。這樣在執(zhí)行parse方法的時候,就可以捕獲到可能的出現(xiàn)的錯誤信息

do {
    let xmlDoc = try parse(myXMLData)
} catch let e as XMLParsingError {
    print("Parsing error: \(e.kind) [\(e.line):\(e.column)]")
} catch {
    print("Other error: \(error)")
}
// Prints "Parsing error: mismatchedTag [19:5]"

Alamofire中的錯誤示例

??刻意看了下Alamofire中的錯誤處理,它用單獨的一個文件AFError來管理使用中的錯誤,其中自定義了枚舉

public enum AFError: Error {
                                encoding process.
    public enum ParameterEncodingFailureReason {
        case missingURL
        case jsonEncodingFailed(error: Error)
        case propertyListEncodingFailed(error: Error)
    }

    
    public enum MultipartEncodingFailureReason {
        case bodyPartURLInvalid(url: URL)
        case bodyPartFilenameInvalid(in: URL)
        case bodyPartFileNotReachable(at: URL)
        case bodyPartFileNotReachableWithError(atURL: URL, error: Error)
        case bodyPartFileIsDirectory(at: URL)
        case bodyPartFileSizeNotAvailable(at: URL)
        case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error)
        case bodyPartInputStreamCreationFailed(for: URL)

        case outputStreamCreationFailed(for: URL)
        case outputStreamFileAlreadyExists(at: URL)
        case outputStreamURLInvalid(url: URL)
        case outputStreamWriteFailed(error: Error)

        case inputStreamReadFailed(error: Error)
    }

    
    public enum ResponseValidationFailureReason {
        case dataFileNil
        case dataFileReadFailed(at: URL)
        case missingContentType(acceptableContentTypes: [String])
        case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String)
        case unacceptableStatusCode(code: Int)
    }

    
    public enum ResponseSerializationFailureReason {
        case inputDataNil
        case inputDataNilOrZeroLength
        case inputFileNil
        case inputFileReadFailed(at: URL)
        case stringSerializationFailed(encoding: String.Encoding)
        case jsonSerializationFailed(error: Error)
        case propertyListSerializationFailed(error: Error)
    }

    case invalidURL(url: URLConvertible)
    case parameterEncodingFailed(reason: ParameterEncodingFailureReason)
    case multipartEncodingFailed(reason: MultipartEncodingFailureReason)
    case responseValidationFailed(reason: ResponseValidationFailureReason)
    case responseSerializationFailed(reason: ResponseSerializationFailureReason)
}

以此將使用中出現(xiàn)的錯誤進行分類。
??不僅如此,作者還將AFError進行了擴展,增加部分判斷的方法,比如判斷是否是無效的URL:

// MARK: - Error Booleans

extension AFError {
    /// Returns whether the AFError is an invalid URL error.
    public var isInvalidURLError: Bool {
        if case .invalidURL = self { return true }
        return false
    }
}

同時拓展中也遵守了LocalizedError協(xié)議來重寫errorDescription屬性,并且對已經(jīng)分類enum的自定義錯誤類型進行拓展重寫了屬性localizedDescription,這樣就構(gòu)成了項目中完整的錯誤處理機制。比如在Alamofire編碼解析方法方法encode中,有這么一段代碼

do {
            let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)

            if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
                urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
            }

            urlRequest.httpBody = data
        } catch {
            throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
        }

其中就是對于JSON序列化時,通過 do { try } catch 的方式來捕獲錯誤,如果捕獲到,將拋出已經(jīng)自定義好的 AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 類型錯誤。


fatalError

還有一個錯誤相關(guān)的是 fatalError, 蘋果對其的描述:

Unconditionally prints a given message and stops execution.

定義:

/// - Parameters:
///   - message: The string to print. The default is an empty string.
///   - file: The file name to print with `message`. The default is the file
///     where `fatalError(_:file:line:)` is called.
///   - line: The line number to print along with `message`. The default is the
///     line number where `fatalError(_:file:line:)` is called.
public func fatalError(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) -> Never

這個我們估計最常見的地方就是在 init(coder: NSCoder) 中看到它,它的作用如蘋果描述的,無條件的打印出給定的信息同時終止程序。按照喵神的描述,fatalError的存在意義是:

<font size=3>在調(diào)試時我們可以使用斷言來排除類似這樣的問題,但是斷言只會在 Debug 環(huán)境中有效,而在 Release 編譯中所有的斷言都將被禁用。在遇到確實因為輸入的錯誤無法使程序繼續(xù)運行的時候,我們一般考慮以產(chǎn)生致命錯誤 fatalError 的方式來終止程序。</font>

而實際開發(fā)中喵神給出兩個使用的場景:

  1. 父類中的某些方法,不想讓別人調(diào)用,可以在方法中加上fatalError,這樣子類如果想到用必須重寫
  2. 對于其他一切我們不希望別人隨意調(diào)用,但是又不得不去實現(xiàn)的方法,我們都應(yīng)該使用 fatalError 來避免任何可能的誤會。

關(guān)于第二點就是我們常見到的在重寫UIView init(frame:) 時,Xcode會提示需要顯示重寫 init(coder: NSCoder),并且給出默認(rèn)實現(xiàn)的原因:

required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

UIView遵守了協(xié)議 NSCoding,此協(xié)議要求實現(xiàn) init(coder: NSCoder)

public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER

詳細(xì)的場景介紹請看喵神的文章


關(guān)于錯誤處理機制

??鶸之前也想過錯誤處理機制的意義,返回一個狀態(tài)碼不就好了。比如我們打開一個文件,成功了返回一個整數(shù)的描述符,錯誤了就返回-1;或者我們請求聯(lián)網(wǎng),如果參數(shù)有問題,會和后臺約定一個數(shù)字作為錯誤碼,也都很好。然而只是單純的用錯誤碼會面臨兩個問題:

  1. 用錯誤碼來表示是否出錯十分不便,因為函數(shù)本身應(yīng)該返回的正常結(jié)果和錯誤碼混在一起,造成調(diào)用者必須用大量的代碼來判斷是否出錯。
  2. 一旦出錯,還要一級一級上報,直到某個函數(shù)可以處理該錯誤(比如,給用戶輸出一個錯誤信息)。

高級語言的錯誤處理機制就解決了這些問題。

喵神FATALERROR
蘋果文檔Error
廖雪峰python

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • error code(錯誤代碼)=0是操作成功完成。error code(錯誤代碼)=1是功能錯誤。error c...
    Heikki_閱讀 3,439評論 1 9
  • error code(錯誤代碼)=2000是無效的像素格式。error code(錯誤代碼)=2001是指定的驅(qū)動...
    Heikki_閱讀 1,849評論 0 4
  • 原文: Alamofire 4.0 Migration Guide作者: cnoon譯者: kemchenj 譯者...
    kemchenj閱讀 2,986評論 4 12
  • 初中時,我有一個最好的朋友。我們一起上課下課,聊八卦。我去她家過夜,她來我家吃飯。媽媽每次問,她最近怎樣了,好久沒...
    黃馬立閱讀 203評論 0 0
  • 圣誕節(jié)晚上吃飯時我問K,2017的目標(biāo)有哪些。他所說的其中有一條是:通過HSK四級。今日又在微信群里收到母上大人布...
    天漫一閱讀 850評論 0 2