Swift?Error重構(gòu)的基礎(chǔ)示例詳解
Error
在開發(fā)中,往往最容易被忽略的內(nèi)容就是對錯誤的處理。有經(jīng)驗(yàn)的開發(fā)者,能夠?qū)ψ约簩懙拿啃写a負(fù)責(zé),而且非常清楚自己寫的代碼在什么時候會出現(xiàn)異常,這樣就能提前做好錯誤處理。
定義
Swift 里面的Error是一個協(xié)議
public protocol Error : Sendable { }
Sendable: 可以安全地將可發(fā)送類型的值從一個并發(fā)域傳遞到另一個——例如,您可以在調(diào)用參與者的方法時將可發(fā)送值作為參數(shù)傳遞
概述
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.
在Swift的錯誤處理系統(tǒng)中,任何聲明符合Error協(xié)議的類型都可以用來表示錯誤。因?yàn)镋rror協(xié)議沒有它自己的要求,所以您可以對您創(chuàng)建的任何自定義類型聲明一致性。
用枚舉來表示簡單的錯誤
Swift 的枚舉非常適合表示簡單的錯誤。創(chuàng)建一個符合Error
協(xié)議的枚舉,并為每個可能的錯誤提供一個case。如果需要有關(guān)錯誤的其他詳細(xì)信息,可以使用關(guān)聯(lián)值來包含該信息。
/// 聲明一個Int解析的Error enum IntParsingError: Error { /// 超過長度 case overflow /// 無法解析的字符 case invalidInput(String) /// 其他錯誤類型 case other }
extension Int { init(validating input: String) throws { for item in input { guard let _ = item.toInt() else { throw IntParsingError.invalidInput(String(item)) } } if let int = input.toInt() { self = int } else { throw IntParsingError.other } } } extension Character { func toInt() -> Int? { let str = String(self) if let int = Int(str) { return int } return nil } } extension String { public func toInt() -> Int? { if let num = NumberFormatter().number(from: self) { return num.intValue } else { return nil } } }
let money: String = "100塊錢" let a = try? Int(validating: money)
此時的 a 是一個Int?類型, 初始化失敗就返回nil.
do { let price = try Int(validating: money) print(price) } catch IntParsingError.invalidInput(let invalid) { print("Invalid character: '(invalid)'") } catch IntParsingError.overflow { print("Overflow error") } catch { print("Other error") }
此時的price是一個Int類型, 如果轉(zhuǎn)換失敗,就會拋出異常。
用結(jié)構(gòu)體或其他類型表示復(fù)雜的錯誤
以下示例在解析時,使用結(jié)構(gòu)來表示錯誤,包括發(fā)生錯誤的文件,方法和行號:
struct ParseError: Error { enum errorKind { case pathError case InvalidFormat case other } let file: String let method: String let line: Int let type: errorKind } func parse(_ source: String) throws -> Int { throw ParseError.init( file: "Users/Mccc/Log/Vip.swift", method: "LogMethod", line: 12, type: .InvalidFormat) }
使用模式匹配來有條件地捕獲錯誤。以下是如何捕獲函數(shù)拋出的任何錯誤:
do { let info = try parse("123") print(info) } catch let e as ParseError { print("Parsing error: (e.type) [(e.file) : (e.method) : (e.line)]") } catch { print("Other error: (error)") }
處理Error的三種方式
- 通過 try?忽略Error
- 通過
do - catch
捕捉Error
- 不捕捉
Error
,在當(dāng)前函數(shù)增加throws
聲明,Error
將自動拋給上層函數(shù)。如果最頂層函數(shù)(main 函數(shù))依然沒有捕捉Error
,那么程序?qū)⒔K止
相關(guān)的一些關(guān)鍵詞
rethrows & throws
throws
關(guān)鍵字首先用在函數(shù)申明中,放在返回類型的前面,比如標(biāo)準(zhǔn)庫中map的函數(shù)簽名。
@frozen public struct Array<Element> { @inlinable public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] }
然后在函數(shù)內(nèi)部,如果出現(xiàn)可能的異常,就可以拋出異常。
enum NegativeError: Error { /// 負(fù)數(shù) case negative } let nums = [1, 2, 3, 4, -5] do { let strNums = try nums.map { (num) throws -> String in if num >= 0 { return String(num) } else { throw NegativeError.negative } } print(strNums) // Will no print } catch let err { print(err) }
- throws::在函數(shù)或者方法中拋出異常,讓調(diào)用者必須明確地處理可能的異常.
- rethrows::本身并不拋出異?;蛘咛幚懋惓#渲黄鸬絺鬟f異常的作用.
func methodThrows(num: Int) throws { if num < 0 { print("Throwing!") throw error } print("Executed!") } func methodRethrows(num: Int, f: (Int) throws -> ()) rethrows { try f(num) } do { try methodRethrows(num: 1, f: methodThrows) } catch _ { }
簡單理解的話你可以將 rethrows
看做是 throws
的“子類”,rethrows
的方法可以用來重載那些被標(biāo)為 throws
的方法或者參數(shù),或者用來滿足被標(biāo)為 throws
的接口,但是反過來不行。
try / try!/ try? / defer
- try: 和可選類型相似,編譯器強(qiáng)制我們在使用可能跑出錯誤的房時使用try關(guān)鍵字。需要和
do {} cathc {}
結(jié)合使用。 - try?。?類似于可選型中的強(qiáng)制解包,同樣不會對錯誤進(jìn)行處理,但是一旦方法拋出錯誤,就會造成程序的崩潰
- try?:有點(diǎn)類似于可選型中的可選鏈,如果方法正確,則完整執(zhí)行;如果跑出錯誤,則方法提前結(jié)束,但不會拋出錯誤進(jìn)行處理。
- defer:將必須執(zhí)行的邏輯放在defer{}中,可以保證無論方法從哪個出口結(jié)束,defer{}中的代碼都會執(zhí)行,通常會將 defer{ } 放在方法體的最上方,defer代碼段總是在方法生命周期的最后才執(zhí)行。
fatalError
無條件地打印給定的消息并停止執(zhí)行。
fatalError("something wrong")
fatalError的存在意義是:
在調(diào)試時我們可以使用斷言來排除類似這樣的問題,但是斷言只會在 Debug 環(huán)境中有效,而在 Release 編譯中所有的斷言都將被禁用。在遇到確實(shí)因?yàn)檩斎氲腻e誤無法使程序繼續(xù)運(yùn)行的時候,我們一般考慮以產(chǎn)生致命錯誤 fatalError 的方式來終止程序。
- 父類中的某些方法,不想讓別人調(diào)用,可以在方法中加上fatalError,這樣子類如果想到用必須重寫
- 對于其他一切我們不希望別人隨意調(diào)用,但是又不得不去實(shí)現(xiàn)的方法,我們都應(yīng)該使用 fatalError 來避免任何可能的誤會。
Error相關(guān)的協(xié)議
聲明一個汽車的結(jié)構(gòu)體:
struct Car { }
定義一個汽車不能行駛的錯誤。
extension Car { enum TroubleError: Error { /// 癱瘓:車輛無法行駛 case paralysis /// 油量不足 case lackOilWarning /// 超員:減員之后可以繼續(xù)行駛。 case overcrowding(Int) } }
LocalizedError
描述一個錯誤,該錯誤提供描述錯誤發(fā)生原因的本地化消息,并提供有關(guān)該錯誤的更多信息。
public protocol LocalizedError : Error { /// 提供描述錯誤的本地化消息 var errorDescription: String? { get } /// 發(fā)生錯誤的原因 var failureReason: String? { get } /// 如何恢復(fù)的提示 var recoverySuggestion: String? { get } /// 其他幫助文本 var helpAnchor: String? { get } }
extension Car.TroubleError: LocalizedError { /// 提供描述錯誤的本地化消息 var errorDescription: String? { switch self { case .paralysis: return NSLocalizedString("汽車已經(jīng)癱瘓,無法行駛", comment: "呼叫拖車維修") case .lackOilWarning: return NSLocalizedString("油量不足", comment: "清前往加油") case .overcrowding(let count): return NSLocalizedString("乘客超載,超載人數(shù):(count)", comment: "超員部分乘客下車") } } /// 發(fā)生錯誤的原因 var failureReason: String? { switch self { case .paralysis: return "汽車已經(jīng)癱瘓,無法行駛" case .lackOilWarning: return "油量不足" case .overcrowding(let count): return "乘客超載,超載人數(shù):(count)" } } /// 如何恢復(fù)的提示 var recoverySuggestion: String? { switch self { case .paralysis: return "尋找緊急修車方法" case .lackOilWarning: return "去加油站加油" case .overcrowding(let count): return "把超載的人數(shù)(count)人趕下車" } } /// 其他幫助文本 var helpAnchor: String? { switch self { case .paralysis: return "緊急修車電話:0632-2347232" case .lackOilWarning: return "地圖搜索加油站" case .overcrowding(_): return "禁止超載" } } }
CustomNSError
Error ? NSError
// 初始化一個NSError let errorOC = NSError.init(domain: "intsig.qxb", code: 1000, userInfo: nil) // 轉(zhuǎn)換為Error let swiftError = errorOC as Error print(swiftError) print(swiftError.localizedDescription) // 轉(zhuǎn)換為NSError let error = swiftError as NSError
一直認(rèn)為 NSError ? Error ? NSError 可以無障礙轉(zhuǎn)換的。自從收到這個crash:
0 libswiftCore.dylib __swift_stdlib_bridgeErrorToNSError + 40 1 projectName loadDataDidFailed (文件名.swift:69) ... ...
在各個渠道也沒找到具體原因。 只是建議使用CustomNSError來處理。 如有知道具體原因的同學(xué),可以評論回復(fù)一下。
描述特定提供域、代碼和用戶信息字典的錯誤類型。
public protocol CustomNSError : Error { /// The domain of the error. static var errorDomain: String { get } /// The error code within the given domain. var errorCode: Int { get } /// The user-info dictionary. var errorUserInfo: [String : Any] { get } }
extension Car.TroubleError: CustomNSError { static var errorDomain: String { return "Domain" } var errorCode: Int { switch self { case .paralysis: return 1000 case .lackOilWarning: return 1001 case .overcrowding(_): return 1002 } } var errorUserInfo: [String : Any] { return [:] } }
轉(zhuǎn)成NSError
extension Car.TroubleError { func toNSError() -> NSError { NSError.init(domain: Car.TroubleError.errorDomain, code: errorCode, userInfo: errorUserInfo) } }
RecoverableError
可以通過向用戶提供幾個潛在恢復(fù)選項(xiàng)來恢復(fù)的錯誤。這主要在使用 AppKit 的 macOS應(yīng)用 中使用.
extension Car.TroubleError: RecoverableError { /// 在用戶請求時執(zhí)行恢復(fù)來恢復(fù)的錯誤。這主要在使用 AppKit 的 macOS應(yīng)用 中使用. func attemptRecovery(optionIndex recoveryOptionIndex: Int) -> Bool { if recoveryOptionIndex == 0 { // 呼叫緊急車輛救援 return false } else if recoveryOptionIndex == 1 { // 前往加油站加油 return true } else if recoveryOptionIndex == 2 { // 處理超載情況 return true } fatalError("something wrong") } /// 提供提供給用戶的一組可能的恢復(fù)選項(xiàng) var recoveryOptions: [String] { return ["呼叫緊急車輛救援", "前往加油站加油", "處理超載情況"] } }
KingfisherError
Kingfisher的錯誤封裝很經(jīng)典,是使用swift中enum的一個典型案例。讀完這篇文章,一定能讓大家對swift的枚舉和Error的使用有一個更深的理解,同時增加一些枚舉的高級使用技巧。
英文原義:
Represents all the errors which can happen in Kingfisher framework. Kingfisher related methods always throw a
KingfisherError
or invoke the callback withKingfisherError
as its error type. To handle errors from Kingfisher, you switch over the error to get a reason catalog, then switch over the reason to know error detail.
中文翻譯:
KingfisherError 表示在 Kingfisher框架中可能發(fā)生的所有錯誤。與 Kingfisher 相關(guān)的方法總是拋出一個 KingfisherError 或者以 KingfisherError 作為錯誤類型調(diào)用回調(diào)。要處理來自 Kingfisher 的錯誤,需要 switch 錯誤以獲取原因目錄,然后 switch 原因了解錯誤細(xì)節(jié)。
public enum KingfisherError: Error { // 表示網(wǎng)絡(luò)請求階段的錯誤原因 case requestError(reason: RequestErrorReason) // 表示網(wǎng)絡(luò)響應(yīng)階段的錯誤原因 case responseError(reason: ResponseErrorReason) // 表示 Kingfisher 緩存系統(tǒng)中的錯誤 case cacheError(reason: CacheErrorReason) // 表示圖像處理階段的錯誤原因 case processorError(reason: ProcessorErrorReason) // 表示在視圖相關(guān)類中設(shè)置圖像時出現(xiàn)錯誤的原因 case imageSettingError(reason: ImageSettingErrorReason) }
關(guān)聯(lián)值設(shè)計(jì)的五個枚舉 RequestErrorReason,ResponseErrorReason,CacheErrorReason,ProcessorErrorReason,ImageSettingErrorReason
他們是定義在 KingfisherError 中獨(dú)立的枚舉,他們之間是包含和被包含的關(guān)系,理解這一點(diǎn)很重要,因?yàn)橛辛诉@種包含的管理,在使用中就需要通過KingfisherError.RequestErrorReason
這種方式進(jìn)行操作。
那么最重要的問題就是,如何把上邊5個獨(dú)立的枚舉進(jìn)行串聯(lián)呢?Kingfisher巧妙的地方就在這里,有5個獨(dú)立的枚舉,分別代表5大錯誤類型。也就是說這個框架肯定有這5大錯誤模塊,我們只需要給KingfisherError設(shè)計(jì)5個子選項(xiàng),每個子選項(xiàng)關(guān)聯(lián)上這5個獨(dú)立枚舉的值就ok了。
這個設(shè)計(jì)真的很巧妙,試想,如果把所有的錯誤都放到KingfisherError中,就顯得非常冗余。大家好好體會體會在swift下這么設(shè)計(jì)的妙用。
RequestErrorReason
英文原義:
Represents the error reason during networking request phase.
emptyRequest: The request is empty. Code 1001.
invalidURL: The URL of request is invalid. Code 1002.
taskCancelled: The downloading task is cancelled by user. Code 1003.
中文翻譯:
表示網(wǎng)絡(luò)請求階段的錯誤原因.
emptyRequest: 請求為空。代碼1001
invalidURL: 請求的URL無效。代碼1002
taskCancelled: 下載任務(wù)被用戶取消。代碼1003
public enum KingfisherError: Error { public enum RequestErrorReason { case emptyRequest case invalidURL(request: URLRequest) case taskCancelled(task: SessionDataTask, token: SessionDataTask.CancelToken) } }
通過 RequestErrorReason
我們能夠很清楚的看出來這是一個請求錯誤的原因。大家注意reason
這個詞,在命名中,有或者沒有這個詞,表達(dá)的意境完全不同,因此,Kingfisher 的厲害就體現(xiàn)在這些細(xì)節(jié)之中。
RequestErrorReason 本身是一個枚舉,同時它又被包含在 KingfisherError 中,這說明枚舉之中可以有另一個枚舉 。那么像這種情況我們怎么使用呢?看下邊的代碼:
let reason = KingfisherError.RequestErrorReason.emptyRequest
枚舉的訪問是一級一級進(jìn)行的。我們再看這行代碼:case invalidURL(request: URLRequest)
并不是函數(shù),它是枚舉的一個普通的子選項(xiàng)。(request: URLRequest)
是它的一個關(guān)聯(lián)值,相對于任何一個子選項(xiàng),我們都可以關(guān)聯(lián)任何值,它的意義就在于,把這些值與子選項(xiàng)進(jìn)行綁定,方便在需要的時候調(diào)用。
ResponseErrorReason
英文原義:
Represents the error reason during networking response phase.
invalidURLResponse: The response is not a valid URL response. Code 2001.
invalidHTTPStatusCode: The response contains an invalid HTTP status code. Code 2002.
URLSessionError: An error happens in the system URL session. Code 2003.
dataModifyingFailed: Data modifying fails on returning a valid data. Code 2004.
noURLResponse: The task is done but no URL response found. Code 2005.
中文翻譯:
表示網(wǎng)絡(luò)響應(yīng)階段的錯誤原因。
invalidURLResponse: 該響應(yīng)不是有效的URL響應(yīng)。代碼2001。
invalidHTTPStatusCode: 響應(yīng)包含無效的HTTP狀態(tài)碼。代碼2002。
URLSessionError: 統(tǒng)URL會話中發(fā)生錯誤。代碼2003。
dataModifyingFailed: 返回有效數(shù)據(jù)時數(shù)據(jù)修改失敗。代碼2004。
noURLResponse: 任務(wù)完成但沒有找到URL響應(yīng)。代碼2005。
public enum KingfisherError: Error { public enum ResponseErrorReason { case invalidURLResponse(response: URLResponse) case invalidHTTPStatusCode(response: HTTPURLResponse) case URLSessionError(error: Error) case dataModifyingFailed(task: SessionDataTask) case noURLResponse(task: SessionDataTask) } }
CacheErrorReason
英文原義:
Represents the error reason during Kingfisher caching system.
fileEnumeratorCreationFailed: Cannot create a file enumerator for a certain disk URL. Code 3001.
invalidFileEnumeratorContent: Cannot get correct file contents from a file enumerator. Code 3002.
invalidURLResource: The file at target URL exists, but its URL resource is unavailable. Code 3003.
cannotLoadDataFromDisk: The file at target URL exists, but the data cannot be loaded from it. Code 3004.
cannotCreateDirectory: Cannot create a folder at a given path. Code 3005.
imageNotExisting: The requested image does not exist in cache. Code 3006.
cannotConvertToData: Cannot convert an object to data for storing. Code 3007.
cannotSerializeImage: Cannot serialize an image to data for storing. Code 3008.
cannotCreateCacheFile: Cannot create the cache file at a certain fileURL under a key. Code 3009.
cannotSetCacheFileAttribute: Cannot set file attributes to a cached file. Code 3010.
中文翻譯:
在 Kingfisher 緩存系統(tǒng)中出現(xiàn)的錯誤。
fileEnumeratorCreationFailed: 無法為某個磁盤URL創(chuàng)建文件枚舉器。代碼3001
invalidFileEnumeratorContent: 無法從文件枚舉器獲取正確的文件內(nèi)容。代碼3002
invalidURLResource: 目標(biāo)URL上的文件存在,但是它的URL資源不可用。代碼3003
cannotLoadDataFromDisk: 目標(biāo)URL上的文件存在,但無法從中加載數(shù)據(jù)。代碼3004
cannotCreateDirectory: 無法在給定路徑上創(chuàng)建文件夾。代碼3005
imageNotExisting: 緩存中不存在所請求的圖片。代碼3006
cannotConvertToData: 無法將對象轉(zhuǎn)換為用于存儲的數(shù)據(jù)。代碼3007
cannotSerializeImage: 無法將圖片序列化為要存儲的數(shù)據(jù)。代碼3008
cannotCreateCacheFile: 無法在某個鍵下的某個文件上創(chuàng)建緩存文件。代碼3009
cannotSetCacheFileAttribute: Cannot set file attributes to a cached file. Code 3010
public enum KingfisherError: Error { public enum CacheErrorReason { case fileEnumeratorCreationFailed(url: URL) case invalidFileEnumeratorContent(url: URL) case invalidURLResource(error: Error, key: String, url: URL) case cannotLoadDataFromDisk(url: URL, error: Error) case cannotCreateDirectory(path: String, error: Error) case imageNotExisting(key: String) case cannotConvertToData(object: Any, error: Error) case cannotSerializeImage(image: KFCrossPlatformImage?, original: Data?, serializer: CacheSerializer) case cannotCreateCacheFile(fileURL: URL, key: String, data: Data, error: Error) case cannotSetCacheFileAttribute(filePath: String, attributes: [FileAttributeKey : Any], error: Error) } }
ProcessorErrorReason
英文原義:
Represents the error reason during image processing phase.
processingFailed: Image processing fails. There is no valid output image from the processor. Code 4001.
中文翻譯:
代表在圖片處理階段的錯誤原因。
processingFailed: 圖像處理失敗。處理器沒有有效的輸出圖像。代碼4001
public enum KingfisherError: Error { public enum ProcessorErrorReason { case processingFailed(processor: ImageProcessor, item: ImageProcessItem) } }
ImageSettingErrorReason
英文原義:
Represents the error reason during image setting in a view related class.
emptySource: The input resource is empty or nil. Code 5001.
notCurrentSourceTask: The source task is finished, but it is not the one expected now. Code 5002.
dataProviderError: An error happens during getting data from an ImageDataProvider. Code 5003.
alternativeSourcesExhausted: No more alternative Source can be used in current loading process. Code 5004
中文翻譯:
表示在視圖相關(guān)類中設(shè)置圖像時出現(xiàn)錯誤的原因。
emptySource: 輸入資源為空或“nil”。代碼5001
notCurrentSourceTask: 源任務(wù)已經(jīng)完成,但不是現(xiàn)在所期望的任務(wù)。代碼5002
dataProviderError: 從 ImageDataProvider 獲取數(shù)據(jù)時發(fā)生錯誤。代碼5003
alternativeSourcesExhausted: 在當(dāng)前加載過程中不能使用更多的替代“源”。它的意思是。使用了 alternativeSources,Kingfisher 嘗試從最初的錯誤恢復(fù),但使用所有給定的替代源仍然失敗。關(guān)聯(lián)的值包含加載過程中遇到的所有錯誤,包括原始源加載錯誤和所有替代源錯誤。
public enum KingfisherError: Error { public enum ImageSettingErrorReason { case emptySource case notCurrentSourceTask(result: RetrieveImageResult?, error: Error?, source: Source) case dataProviderError(provider: ImageDataProvider, error: Error) case alternativeSourcesExhausted([PropagationError]) } }
便捷的檢驗(yàn)方法&屬性
是否任務(wù)被取消
public var isTaskCancelled: Bool { if case .requestError(reason: .taskCancelled) = self { return true } return false }
是否無效的返回狀態(tài)碼
是ResponseErrorReason.invalidHTTPStatusCode
這個case,并且關(guān)聯(lián)的code與給定的一致。
public func isInvalidResponseStatusCode(_ code: Int) -> Bool { if case .responseError(reason: .invalidHTTPStatusCode(let response)) = self { return response.statusCode == code } return false }
是否無效響應(yīng)狀態(tài)碼
public var isInvalidResponseStatusCode: Bool { if case .responseError(reason: .invalidHTTPStatusCode) = self { return true } return false }
是否當(dāng)前任務(wù)
檢查是否為 ImageSettingErrorReason.notCurrentSourceTask
類型錯誤。當(dāng)舊的圖像設(shè)置任務(wù)仍在運(yùn)行而新的圖像設(shè)置任務(wù)啟動時,將設(shè)置新的任務(wù)標(biāo)識符并覆蓋舊的任務(wù)。當(dāng)舊的任務(wù)結(jié)束時,一個 .notCurrentSourceTask
錯誤將會被拋出,讓您知道設(shè)置過程以一定的結(jié)果結(jié)束,但是 image view or button
沒有被設(shè)置。
public var isNotCurrentTask: Bool { if case .imageSettingError(reason: .notCurrentSourceTask(_, _, _)) = self { return true } return false }
localized message describing
在開發(fā)中,如果程序遇到錯誤,我們往往會給用戶展示更加直觀的信息,這就要求我們把錯誤信息轉(zhuǎn)換成易于理解的內(nèi)容。因此我們只要實(shí)現(xiàn)LocalizedError協(xié)議就好了。
extension KingfisherError: LocalizedError { public var errorDescription: String? { switch self { case .requestError(let reason): return reason.errorDescription case .responseError(let reason): return reason.errorDescription case .cacheError(let reason): return reason.errorDescription case .processorError(let reason): return reason.errorDescription case .imageSettingError(let reason): return reason.errorDescription } } } extension KingfisherError: CustomNSError { public var errorCode: Int { switch self { case .requestError(let reason): return reason.errorCode case .responseError(let reason): return reason.errorCode case .cacheError(let reason): return reason.errorCode case .processorError(let reason): return reason.errorCode case .imageSettingError(let reason): return reason.errorCode } } }
通過擴(kuò)展給五大錯誤枚舉,添加描述。
extension KingfisherError.RequestErrorReason { var errorDescription: String? { switch self { case .emptyRequest: return "The request is empty or `nil`." case .invalidURL(let request): return "The request contains an invalid or empty URL. Request: (request)." case .taskCancelled(let task, let token): return "The session task was cancelled. Task: (task), cancel token: (token)." } } var errorCode: Int { switch self { case .emptyRequest: return 1001 case .invalidURL: return 1002 case .taskCancelled: return 1003 } } } extension KingfisherError.ResponseErrorReason { var errorDescription: String? { switch self { case .invalidURLResponse(let response): return "The URL response is invalid: (response)" case .invalidHTTPStatusCode(let response): return "The HTTP status code in response is invalid. Code: (response.statusCode), response: (response)." case .URLSessionError(let error): return "A URL session error happened. The underlying error: (error)" case .dataModifyingFailed(let task): return "The data modifying delegate returned `nil` for the downloaded data. Task: (task)." case .noURLResponse(let task): return "No URL response received. Task: (task)," } } var errorCode: Int { switch self { case .invalidURLResponse: return 2001 case .invalidHTTPStatusCode: return 2002 case .URLSessionError: return 2003 case .dataModifyingFailed: return 2004 case .noURLResponse: return 2005 } } } extension KingfisherError.CacheErrorReason { var errorDescription: String? { switch self { case .fileEnumeratorCreationFailed(let url): return "Cannot create file enumerator for URL: (url)." case .invalidFileEnumeratorContent(let url): return "Cannot get contents from the file enumerator at URL: (url)." case .invalidURLResource(let error, let key, let url): return "Cannot get URL resource values or data for the given URL: (url). " + "Cache key: (key). Underlying error: (error)" case .cannotLoadDataFromDisk(let url, let error): return "Cannot load data from disk at URL: (url). Underlying error: (error)" case .cannotCreateDirectory(let path, let error): return "Cannot create directory at given path: Path: (path). Underlying error: (error)" case .imageNotExisting(let key): return "The image is not in cache, but you requires it should only be " + "from cache by enabling the `.onlyFromCache` option. Key: (key)." case .cannotConvertToData(let object, let error): return "Cannot convert the input object to a `Data` object when storing it to disk cache. " + "Object: (object). Underlying error: (error)" case .cannotSerializeImage(let image, let originalData, let serializer): return "Cannot serialize an image due to the cache serializer returning `nil`. " + "Image: (String(describing:image)), original data: (String(describing: originalData)), " + "serializer: (serializer)." case .cannotCreateCacheFile(let fileURL, let key, let data, let error): return "Cannot create cache file at url: (fileURL), key: (key), data length: (data.count). " + "Underlying foundation error: (error)." case .cannotSetCacheFileAttribute(let filePath, let attributes, let error): return "Cannot set file attribute for the cache file at path: (filePath), attributes: (attributes)." + "Underlying foundation error: (error)." } } var errorCode: Int { switch self { case .fileEnumeratorCreationFailed: return 3001 case .invalidFileEnumeratorContent: return 3002 case .invalidURLResource: return 3003 case .cannotLoadDataFromDisk: return 3004 case .cannotCreateDirectory: return 3005 case .imageNotExisting: return 3006 case .cannotConvertToData: return 3007 case .cannotSerializeImage: return 3008 case .cannotCreateCacheFile: return 3009 case .cannotSetCacheFileAttribute: return 3010 } } } extension KingfisherError.ProcessorErrorReason { var errorDescription: String? { switch self { case .processingFailed(let processor, let item): return "Processing image failed. Processor: (processor). Processing item: (item)." } } var errorCode: Int { switch self { case .processingFailed: return 4001 } } } extension KingfisherError.ImageSettingErrorReason { var errorDescription: String? { switch self { case .emptySource: return "The input resource is empty." case .notCurrentSourceTask(let result, let error, let resource): if let result = result { return "Retrieving resource succeeded, but this source is " + "not the one currently expected. Result: (result). Resource: (resource)." } else if let error = error { return "Retrieving resource failed, and this resource is " + "not the one currently expected. Error: (error). Resource: (resource)." } else { return nil } case .dataProviderError(let provider, let error): return "Image data provider fails to provide data. Provider: (provider), error: (error)" case .alternativeSourcesExhausted(let errors): return "Image setting from alternaive sources failed: (errors)" } } var errorCode: Int { switch self { case .emptySource: return 5001 case .notCurrentSourceTask: return 5002 case .dataProviderError: return 5003 case .alternativeSourcesExhausted: return 5004 } } }
以上就是Swift Error重構(gòu)的基礎(chǔ)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Swift Error重構(gòu)基礎(chǔ)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
用Swift構(gòu)建一個簡單的iOS郵件應(yīng)用的方法
這篇文章主要介紹了用Swift構(gòu)建一個簡單的iOS郵件應(yīng)用的方法,包括查看和標(biāo)記已讀等基本的郵件應(yīng)用功能,需要的朋友可以參考下2015-07-07Swift中Optional值的鏈?zhǔn)秸{(diào)用學(xué)習(xí)筆記
這篇文章主要介紹了Swift中Optional值的鏈?zhǔn)秸{(diào)用學(xué)習(xí)筆記,Optional鏈?zhǔn)荢wift入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2016-07-07SwiftUI 中創(chuàng)建反彈動畫的實(shí)現(xiàn)
這篇文章主要介紹了SwiftUI 中創(chuàng)建反彈動畫的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10SwiftUI?引導(dǎo)頁界面實(shí)現(xiàn)示例
這篇文章主要為大家介紹了SwiftUI?引導(dǎo)頁界面實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09快速排序算法在Swift編程中的幾種代碼實(shí)現(xiàn)示例
快速排序是一種不穩(wěn)定的排序,存在著優(yōu)化空間,這里我們來看快速排序算法在Swift編程中的幾種代碼實(shí)現(xiàn)示例:2016-07-07