同步我的掘金MeR
??鶸學(xué)python看到錯(cuò)誤處理這一章的時(shí)候,就想對(duì)比著swift來研究一下茫陆。
??本文前面是Error蘋果文檔的介紹,然后對(duì)Alamofire中的使用作簡(jiǎn)單介紹作為實(shí)踐擎析;后面還有關(guān)于fatalError和高級(jí)語(yǔ)言錯(cuò)誤處理機(jī)制的理解
Error蘋果文檔
Swift中的Error長(zhǎng)這個(gè)樣子
public protocol Error {
}
extension Error {
}
extension Error where Self.RawValue : SignedInteger {
}
extension Error where Self.RawValue : UnsignedInteger {
}
蘋果文檔對(duì)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.
??從介紹上可以看出遵守這個(gè)Error協(xié)議簿盅,就可以將錯(cuò)誤拋出和捕獲,而且任何自定義的類型都可以遵守此Error協(xié)議揍魂。
??文檔中舉了兩個(gè)例子桨醋,第一個(gè)是自定義枚舉遵守Error來對(duì)Error進(jìn)行分類,下面我們著重看下蘋果爸爸給出的第二個(gè)例子:用一個(gè)遵守Error協(xié)議的結(jié)構(gòu)體來獲取更多的錯(cuò)誤信息现斋。
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)建了一個(gè)遵守Error協(xié)議的結(jié)構(gòu)體 XMLParsingError喜最,帶有三個(gè)屬性來記錄解析XML文件時(shí)出錯(cuò)的錯(cuò)誤類型和行列信息。這樣在執(zhí)行parse方法的時(shí)候庄蹋,就可以捕獲到可能的出現(xiàn)的錯(cuò)誤信息
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中的錯(cuò)誤示例
??刻意看了下Alamofire中的錯(cuò)誤處理瞬内,它用單獨(dú)的一個(gè)文件AFError來管理使用中的錯(cuò)誤,其中自定義了枚舉
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)的錯(cuò)誤進(jìn)行分類限书。
??不僅如此虫蝶,作者還將AFError進(jìn)行了擴(kuò)展,增加部分判斷的方法倦西,比如判斷是否是無(wú)效的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
}
}
同時(shí)拓展中也遵守了LocalizedError協(xié)議來重寫errorDescription屬性能真,并且對(duì)已經(jīng)分類enum的自定義錯(cuò)誤類型進(jìn)行拓展重寫了屬性localizedDescription,這樣就構(gòu)成了項(xiàng)目中完整的錯(cuò)誤處理機(jī)制。比如在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))
}
其中就是對(duì)于JSON序列化時(shí)舟陆,通過 do { try } catch 的方式來捕獲錯(cuò)誤,如果捕獲到耻矮,將拋出已經(jīng)自定義好的 AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 類型錯(cuò)誤。
fatalError
還有一個(gè)錯(cuò)誤相關(guān)的是 fatalError, 蘋果對(duì)其的描述:
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
這個(gè)我們估計(jì)最常見的地方就是在 init(coder: NSCoder) 中看到它忆谓,它的作用如蘋果描述的裆装,無(wú)條件的打印出給定的信息同時(shí)終止程序。按照喵神的描述倡缠,fatalError的存在意義是:
<font size=3>在調(diào)試時(shí)我們可以使用斷言來排除類似這樣的問題哨免,但是斷言只會(huì)在 Debug 環(huán)境中有效,而在 Release 編譯中所有的斷言都將被禁用昙沦。在遇到確實(shí)因?yàn)檩斎氲腻e(cuò)誤無(wú)法使程序繼續(xù)運(yùn)行的時(shí)候琢唾,我們一般考慮以產(chǎn)生致命錯(cuò)誤 fatalError 的方式來終止程序。</font>
而實(shí)際開發(fā)中喵神給出兩個(gè)使用的場(chǎng)景:
- 父類中的某些方法盾饮,不想讓別人調(diào)用采桃,可以在方法中加上fatalError懒熙,這樣子類如果想到用必須重寫
- 對(duì)于其他一切我們不希望別人隨意調(diào)用,但是又不得不去實(shí)現(xiàn)的方法普办,我們都應(yīng)該使用 fatalError 來避免任何可能的誤會(huì)工扎。
關(guān)于第二點(diǎn)就是我們常見到的在重寫UIView init(frame:) 時(shí),Xcode會(huì)提示需要顯示重寫 init(coder: NSCoder)衔蹲,并且給出默認(rèn)實(shí)現(xiàn)的原因:
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
UIView遵守了協(xié)議 NSCoding肢娘,此協(xié)議要求實(shí)現(xiàn) init(coder: NSCoder)
public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER
詳細(xì)的場(chǎng)景介紹請(qǐng)看喵神的文章。
關(guān)于錯(cuò)誤處理機(jī)制
??鶸之前也想過錯(cuò)誤處理機(jī)制的意義舆驶,返回一個(gè)狀態(tài)碼不就好了橱健。比如我們打開一個(gè)文件,成功了返回一個(gè)整數(shù)的描述符沙廉,錯(cuò)誤了就返回-1;或者我們請(qǐng)求聯(lián)網(wǎng)拘荡,如果參數(shù)有問題,會(huì)和后臺(tái)約定一個(gè)數(shù)字作為錯(cuò)誤碼蓝仲,也都很好俱病。然而只是單純的用錯(cuò)誤碼會(huì)面臨兩個(gè)問題:
- 用錯(cuò)誤碼來表示是否出錯(cuò)十分不便,因?yàn)楹瘮?shù)本身應(yīng)該返回的正常結(jié)果和錯(cuò)誤碼混在一起袱结,造成調(diào)用者必須用大量的代碼來判斷是否出錯(cuò)亮隙。
- 一旦出錯(cuò),還要一級(jí)一級(jí)上報(bào)垢夹,直到某個(gè)函數(shù)可以處理該錯(cuò)誤(比如溢吻,給用戶輸出一個(gè)錯(cuò)誤信息)。
高級(jí)語(yǔ)言的錯(cuò)誤處理機(jī)制就解決了這些問題果元。