錯(cuò)誤處理 Alamofire

Alamofire 對錯(cuò)誤的處理考慮使用枚舉,只要結(jié)果可能是有限的集合的情況下,其實(shí)枚舉本身還是數(shù)據(jù)的一種載體海蔽,swift中党窜,枚舉有著很豐富的使用方法.
先總結(jié)一下swfit中enum中的用法:

1.正常用法

enum Movement {
    case Left
    case Right
    case Top
    case Bottom
}
let aMovement = Movement.Left
switch aMovement {
case .Left:
    print("left")
default:
    print("Unknow")
}
if case .Left = aMovement {
    print("Left")
}
if .Left == aMovement {
    print("Left")
}

2.聲明為整型

enum Season: Int {
    case Spring = 0
    case Summer = 1
    case Autumn = 2
    case Winter = 3
}

.3.聲明為字符串類型

enum House: String {
    case ZhangSan = "I am zhangsan"
    case LiSi = "I am lisi"
}
let zs = House.ZhangSan
print(zs.rawValue)
enum CompassPoint: String {
case North, South, East, West
}
let n = CompassPoint.North

4.聲明為浮點(diǎn)類型

enum Constants: Double {
    case π = 3.14159
    case e = 2.71828
    case φ = 1.61803398874
    case λ = 1.30357
}
let pai = Constants.π
print(pai.rawValue)

5.其他類型

enum VNodeFlags : UInt32 {
    case Delete = 0x00000001
    case Write = 0x00000002
    case Extended = 0x00000004
    case Attrib = 0x00000008
    case Link = 0x00000010
    case Rename = 0x00000020
    case Revoke = 0x00000040
    case None = 0x00000080
}

6.enum包含enum

enum Character {

    enum Weapon {
        case Bow
        case Sword
        case Lance
        case Dagger
    }

    enum Helmet {
        case Wooden
        case Iron
        case Diamond
    }

    case Thief
    case Warrior
    case Knight
}

7.結(jié)構(gòu)體和枚舉

struct Scharacter {
    enum CharacterType {
        case Thief
        case Warrior
        case Knight
    }
    enum Weapon {
        case Bow
        case Sword
        case Lance
        case Dagger
    }
    let type: CharacterType
    let weapon: Weapon
}
let sc = Scharacter(type: .Thief, weapon: .Bow)
print(sc.type)

8.值關(guān)聯(lián)

enum Trade {
    case Buy(stock: String, amount: Int)
    case Sell(stock: String, amount: Int)
}
let trade = Trade.Buy(stock: "Car", amount: 100)
if case let Trade.Buy(stock, amount) = trade {
    print("buy \(amount) of \(stock)")
}
enum Trade0 {
    case Buy(String, Int)
    case Sell(String, Int)
}
let trade0 = Trade0.Buy("Car0", 100)
if case let Trade0.Buy(stock, amount) = trade0 {
    print("buy \(amount) of \(stock)")
}

9.枚舉中的函數(shù)

enum Wearable {
    enum Weight: Int {
        case Light = 2
    }

    enum Armor: Int {
        case Light = 2
    }

    case Helmet(weight: Weight, armor: Armor)


    func attributes() -> (weight: Int, armor: Int) {
        switch self {
        case .Helmet(let w, let a):
            return (weight: w.rawValue * 2, armor: a.rawValue * 4)

        }
    }
}

let test = Wearable.Helmet(weight: .Light, armor: .Light).attributes()
print(test)

enum Device {
    case iPad, iPhone, AppleTV, AppleWatch
    func introduced() -> String {
        switch self {
        case .AppleTV: return "\(self) was introduced 2006"
        case .iPhone: return "\(self) was introduced 2007"
        case .iPad: return "\(self) was introduced 2010"
        case .AppleWatch: return "\(self) was introduced 2014"
        }
    }
}
print (Device.iPhone.introduced())

10.枚舉中的屬性

enum Device1 {
    case iPad, iPhone
    var year: Int {
        switch self {
        case .iPad:
            return 2010
        case .iPhone:
            return 2007
    }
    }
}

let iPhone = Device1.iPhone
print(iPhone.year)

ParameterEncodingFailureReason

通過ParameterEncodingFailureReason我們能夠很清楚的看出來這是一個(gè)參數(shù)編碼的錯(cuò)誤原因壤玫。大家注意reason這個(gè)詞,在命名中择镇,有或者沒有這個(gè)詞腻豌,表達(dá)的意境完全不同吝梅,因此惹骂,Alamofire牛逼就體現(xiàn)在這些細(xì)節(jié)之中对粪。

public enum AFError: Error {
    /// The underlying reason the parameter encoding error occurred.
    ///
    /// - missingURL:                 The URL request did not have a URL to encode.
    /// - jsonEncodingFailed:         JSON serialization failed with an underlying system error during the
    ///                               encoding process.
    /// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during
    ///                               encoding process.
    public enum ParameterEncodingFailureReason {
        case missingURL
        case jsonEncodingFailed(error: Error)
        case propertyListEncodingFailed(error: Error)
    }
 }

ParameterEncodingFailureReason本身是一個(gè)enum,同時(shí)牍帚,它又被包含在AFError之中乳蛾,這說明枚舉之中可以有另一個(gè)枚舉肃叶。那么像這種情況我們怎么使用呢因惭?看下邊的代碼:

let parameterErrorReason = AFError.ParameterEncodingFailureReason.missingURL

枚舉的訪問是一級一級進(jìn)行的。我們再看這行代碼:case jsonEncodingFailed(error: Error)浸锨。jsonEncodingFailed(error: Error)并不是函數(shù)柱搜,就是枚舉的一個(gè)普通的子選項(xiàng)剥险。(error: Error)是它的一個(gè)關(guān)聯(lián)值表制,相對于任何一個(gè)子選項(xiàng)么介,我們都可以關(guān)聯(lián)任何值,它的意義就在于设拟,把這些值與子選項(xiàng)進(jìn)行綁定纳胧,方便在需要的時(shí)候調(diào)用帘撰。我們會在下邊講解如何獲取關(guān)聯(lián)值摧找。

參數(shù)編碼有一下幾種方式:

把參數(shù)編碼到URL中
把參數(shù)編碼到httpBody中
Alamofire中是如何進(jìn)行參數(shù)編碼的,這方面的內(nèi)容會在后續(xù)的ParameterEncoding.swift這一篇文章中給出詳細(xì)的解釋唤衫。那么編碼失敗的原因可能為:

missingURL 給定的urlRequest.url為nil的情況拋出錯(cuò)誤
jsonEncodingFailed(error: Error) 當(dāng)選擇把參數(shù)編碼成JSON格式的情況下绵脯,參數(shù)JSON化拋出的錯(cuò)誤
propertyListEncodingFailed(error: Error) 這個(gè)同上
綜上所述蛆挫,ParameterEncodingFailureReason封裝了參數(shù)編碼的錯(cuò)誤悴侵,可能出現(xiàn)的錯(cuò)誤類型為Error可免,說明這些所謂一般是調(diào)用系統(tǒng)Api產(chǎn)生的錯(cuò)誤做粤。

MultipartEncodingFailureReason

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)
    }

多部分編碼錯(cuò)誤一般發(fā)生在上傳或下載請求中對數(shù)據(jù)的處理過程中怕品,這里邊最重要的是對上傳數(shù)據(jù)的處理過程肉康,會在后續(xù)的MultipartFormData.swift這一篇文章中給出詳細(xì)的解釋吼和,我們就簡單的分析下MultipartEncodingFailureReason子選項(xiàng)錯(cuò)誤出現(xiàn)的原因:

bodyPartURLInvalid(url: URL) 上傳數(shù)據(jù)時(shí)炫乓,可以通過fileURL的方式,讀取本地文件數(shù)據(jù)光督,如果fileURL不可用结借,就會拋出這個(gè)錯(cuò)誤
bodyPartFilenameInvalid(in: URL) 如果使用fileURL的lastPathComponent或者pathExtension獲取filename為空拋出的錯(cuò)誤
bodyPartFileNotReachable(at: URL) 通過fileURL不能訪問數(shù)據(jù)船老,也就是不可達(dá)的
bodyPartFileNotReachableWithError(atURL: URL, error: Error) 這個(gè)不同于bodyPartFileNotReachable(at: URL),當(dāng)嘗試檢測fileURL是不是可達(dá)的情況下拋出的錯(cuò)誤
bodyPartFileIsDirectory(at: URL) 當(dāng)fileURL是一個(gè)文件夾時(shí)拋出錯(cuò)誤
bodyPartFileSizeNotAvailable(at: URL) 當(dāng)使用系統(tǒng)Api獲取fileURL指定文件的size出現(xiàn)錯(cuò)誤
bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error) 查詢fileURL指定文件size出現(xiàn)錯(cuò)誤
bodyPartInputStreamCreationFailed(for: URL) 通過fileURL創(chuàng)建inputStream出現(xiàn)錯(cuò)誤
outputStreamCreationFailed(for: URL) 當(dāng)嘗試把編碼后的數(shù)據(jù)寫入到硬盤時(shí)柳畔,創(chuàng)建outputStream出現(xiàn)錯(cuò)誤
outputStreamFileAlreadyExists(at: URL) 數(shù)據(jù)不能被寫入薪韩,因?yàn)橹付ǖ膄ileURL已經(jīng)存在
outputStreamURLInvalid(url: URL) fileURL不是一個(gè)file URL
outputStreamWriteFailed(error: Error) 數(shù)據(jù)流寫入錯(cuò)誤
inputStreamReadFailed(error: Error) 數(shù)據(jù)流讀入錯(cuò)誤
綜上所述,這些錯(cuò)誤基本上都跟數(shù)據(jù)的操作相關(guān)罗捎,這個(gè)在后續(xù)會做出很詳細(xì)的說明桨菜。

ResponseValidationFailureReason

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

Alamofire不管請求是否成功倒得,都會返回response霞掺。它提供了驗(yàn)證ContentType和StatusCode的功能讹躯,關(guān)于驗(yàn)證蜀撑,再后續(xù)的文章中會有詳細(xì)的解答酷麦,我們先看看這些原因:

dataFileNil 保存數(shù)據(jù)的URL不存在沃饶,這種情況一般出現(xiàn)在下載任務(wù)中,指的是下載代理中的fileURL缺失
dataFileReadFailed(at: URL) 保存數(shù)據(jù)的URL無法讀取數(shù)據(jù)琴昆,同上
missingContentType(acceptableContentTypes: [String]) 服務(wù)器返回的response不包含ContentType且提供的acceptableContentTypes不包含通配符(通配符表示可以接受任何類型)
unacceptableContentType(acceptableContentTypes: [String], responseContentType: String) ContentTypes不匹配
unacceptableStatusCode(code: Int) StatusCode不匹配

ResponseSerializationFailureReason

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)
}

我們在上篇中已經(jīng)提到业舍,Alamofire支持把服務(wù)器的response序列成幾種數(shù)據(jù)格式舷暮。

response 直接返回HTTPResponse下面,未序列化
responseData 序列化為Data
responseJSON 序列化為Json
responseString 序列化為字符串
responsePropertyList 序列化為Any
那么在序列化的過程中沥割,很可能會發(fā)生下邊的錯(cuò)誤:

inputDataNil 服務(wù)器返回的response沒有數(shù)據(jù)
inputDataNilOrZeroLength 服務(wù)器返回的response沒有數(shù)據(jù)或者數(shù)據(jù)的長度是0
inputFileNil 指向數(shù)據(jù)的URL不存在
inputFileReadFailed(at: URL) 指向數(shù)據(jù)的URL無法讀取數(shù)據(jù)

AFError

上邊內(nèi)容中介紹的ParameterEncodingFailureReason MultipartEncodingFailureReason ResponseValidationFailureReason和 ResponseSerializationFailureReason机杜,他們是定義在AFError中獨(dú)立的枚舉,他們之間是包含和被包含的關(guān)系,理解這一點(diǎn)很重要陡叠,因?yàn)橛辛诉@種包含的管理枉阵,在使用中就需要通過AFError.ParameterEncodingFailureReason這種方式進(jìn)行操作兴溜。

那么最重要的問題就是耻陕,如何把上邊4個(gè)獨(dú)立的枚舉進(jìn)行串聯(lián)呢?Alamofire巧妙的地方就在這里膘怕,有4個(gè)獨(dú)立的枚舉岛心,分別代表4大錯(cuò)誤忘古。也就是說這個(gè)網(wǎng)絡(luò)框架肯定有這4大錯(cuò)誤模塊髓堪,我們只需要給AFError設(shè)計(jì)4個(gè)子選項(xiàng),每個(gè)子選項(xiàng)關(guān)聯(lián)上上邊4個(gè)獨(dú)立枚舉的值就ok了骤菠。

這個(gè)設(shè)計(jì)真的很巧妙商乎,試想鹉戚,如果把所有的錯(cuò)誤都放到AFError中专控,就顯得非常冗余伦腐。那么下邊的代碼就呼之欲出了柏蘑,大家好好體會體會在swift下這么設(shè)計(jì)的妙用:

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

AFError的擴(kuò)展

也許在開發(fā)中咳焚,我們完成了上邊的代碼就認(rèn)為夠用了革半,但對于一個(gè)開源框架而言,遠(yuǎn)遠(yuǎn)是不夠的延刘。我們一點(diǎn)點(diǎn)進(jìn)行剖析:

現(xiàn)在給定一條數(shù)據(jù):

 func findErrorType(error: AFError) {

  }

我只需要知道這個(gè)error是不是參數(shù)編碼錯(cuò)誤访娶,應(yīng)該怎么辦崖疤?因此為AFError提供5個(gè)布爾類型的屬性劫哼,專門用來獲取當(dāng)前的錯(cuò)誤是不是某個(gè)指定的類型权烧。這個(gè)功能的實(shí)現(xiàn)比較簡單般码,代碼如下:

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

    /// Returns whether the AFError is a parameter encoding error. When `true`, the `underlyingError` property will
    /// contain the associated value.
    public var isParameterEncodingError: Bool {
        if case .parameterEncodingFailed = self { return true }
        return false
    }

    /// Returns whether the AFError is a multipart encoding error. When `true`, the `url` and `underlyingError` properties
    /// will contain the associated values.
    public var isMultipartEncodingError: Bool {
        if case .multipartEncodingFailed = self { return true }
        return false
    }

    /// Returns whether the `AFError` is a response validation error. When `true`, the `acceptableContentTypes`,
    /// `responseContentType`, and `responseCode` properties will contain the associated values.
    public var isResponseValidationError: Bool {
        if case .responseValidationFailed = self { return true }
        return false
    }

    /// Returns whether the `AFError` is a response serialization error. When `true`, the `failedStringEncoding` and
    /// `underlyingError` properties will contain the associated values.
    public var isResponseSerializationError: Bool {
        if case .responseSerializationFailed = self { return true }
        return false
    }
}

總而言之宫静,這些都是給AFError這個(gè)枚舉擴(kuò)展的屬性券时,還包含下邊這些屬性
urlConvertible: URLConvertible? 獲取某個(gè)屬性橘洞,這個(gè)屬性實(shí)現(xiàn)了URLConvertible協(xié)議炸枣,在AFError中只有case invalidURL(url: URLConvertible)這個(gè)選項(xiàng)符合要求

/// The `URLConvertible` associated with the error.
      public var urlConvertible: URLConvertible? {
          switch self {
          case .invalidURL(let url):
              return url
          default:
              return nil
          }
      }

url: URL? 獲取AFError中的URL适肠,當(dāng)然這個(gè)URL只跟MultipartEncodingFailureReason這個(gè)子選項(xiàng)有關(guān)

/// The `URL` associated with the error.
      public var url: URL? {
          switch self {
          case .multipartEncodingFailed(let reason):
              return reason.url
          default:
              return nil
          }
      }

underlyingError: Error? AFError中封裝的所有的可能出現(xiàn)的錯(cuò)誤中迂猴,并不是每種可能都會返回Error這個(gè)錯(cuò)誤信息沸毁,因此這個(gè)屬性是可選的

/// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`,
      /// `.multipartEncodingFailed` or `.responseSerializationFailed` error.
      public var underlyingError: Error? {
          switch self {
          case .parameterEncodingFailed(let reason):
              return reason.underlyingError
          case .multipartEncodingFailed(let reason):
              return reason.underlyingError
          case .responseSerializationFailed(let reason):
              return reason.underlyingError
          default:
              return nil
          }
      }

acceptableContentTypes: [String]? 可接受的ContentType

/// The response `Content-Type` of a `.responseValidationFailed` error.
      public var responseContentType: String? {
          switch self {
          case .responseValidationFailed(let reason):
              return reason.responseContentType
          default:
              return nil
          }
      }

responseCode: Int? 響應(yīng)碼

/// The response code of a `.responseValidationFailed` error.
  public var responseCode: Int? {
      switch self {
      case .responseValidationFailed(let reason):
          return reason.responseCode
      default:
          return nil
      }
  }

failedStringEncoding: String.Encoding? 錯(cuò)誤的字符串編碼

/// The `String.Encoding` associated with a failed `.stringResponse()` call.
      public var failedStringEncoding: String.Encoding? {
          switch self {
          case .responseSerializationFailed(let reason):
              return reason.failedStringEncoding
          default:
              return nil
          }
      }

這里是一個(gè)小的分割線,在上邊屬性的獲取中搂誉,也是用到了下邊代碼中的擴(kuò)展功能:

extension AFError.ParameterEncodingFailureReason {
      var underlyingError: Error? {
          switch self {
          case .jsonEncodingFailed(let error), .propertyListEncodingFailed(let error):
              return error
          default:
              return nil
          }
      }
  }

  extension AFError.MultipartEncodingFailureReason {
      var url: URL? {
          switch self {
          case .bodyPartURLInvalid(let url), .bodyPartFilenameInvalid(let url), .bodyPartFileNotReachable(let url),
               .bodyPartFileIsDirectory(let url), .bodyPartFileSizeNotAvailable(let url),
               .bodyPartInputStreamCreationFailed(let url), .outputStreamCreationFailed(let url),
               .outputStreamFileAlreadyExists(let url), .outputStreamURLInvalid(let url),
               .bodyPartFileNotReachableWithError(let url, _), .bodyPartFileSizeQueryFailedWithError(let url, _):
              return url
          default:
              return nil
          }
      }

      var underlyingError: Error? {
          switch self {
          case .bodyPartFileNotReachableWithError(_, let error), .bodyPartFileSizeQueryFailedWithError(_, let error),
               .outputStreamWriteFailed(let error), .inputStreamReadFailed(let error):
              return error
          default:
              return nil
          }
      }
  }

  extension AFError.ResponseValidationFailureReason {
      var acceptableContentTypes: [String]? {
          switch self {
          case .missingContentType(let types), .unacceptableContentType(let types, _):
              return types
          default:
              return nil
          }
      }

      var responseContentType: String? {
          switch self {
          case .unacceptableContentType(_, let responseType):
              return responseType
          default:
              return nil
          }
      }

      var responseCode: Int? {
          switch self {
          case .unacceptableStatusCode(let code):
              return code
          default:
              return nil
          }
      }
  }

  extension AFError.ResponseSerializationFailureReason {
      var failedStringEncoding: String.Encoding? {
          switch self {
          case .stringSerializationFailed(let encoding):
              return encoding
          default:
              return nil
          }
      }

      var underlyingError: Error? {
          switch self {
          case .jsonSerializationFailed(let error), .propertyListSerializationFailed(let error):
              return error
          default:
              return nil
          }
      }
  }

錯(cuò)誤描述

在開發(fā)中拂檩,如果程序遇到錯(cuò)誤稻励,我們往往會給用戶展示更加直觀的信息,這就要求我們把錯(cuò)誤信息轉(zhuǎn)換成易于理解的內(nèi)容加矛。因此我們只要實(shí)現(xiàn)LocalizedError協(xié)議就好了。這里邊的內(nèi)容很簡單毁腿,在這里就直接把代碼寫上了狸棍,不做分析

extension AFError: LocalizedError {
    public var errorDescription: String? {
        switch self {
        case .invalidURL(let url):
            return "URL is not valid: \(url)"
        case .parameterEncodingFailed(let reason):
            return reason.localizedDescription
        case .multipartEncodingFailed(let reason):
            return reason.localizedDescription
        case .responseValidationFailed(let reason):
            return reason.localizedDescription
        case .responseSerializationFailed(let reason):
            return reason.localizedDescription
        }
    }
}

extension AFError.ParameterEncodingFailureReason {
    var localizedDescription: String {
        switch self {
        case .missingURL:
            return "URL request to encode was missing a URL"
        case .jsonEncodingFailed(let error):
            return "JSON could not be encoded because of error:\n\(error.localizedDescription)"
        case .propertyListEncodingFailed(let error):
            return "PropertyList could not be encoded because of error:\n\(error.localizedDescription)"
        }
    }
}

extension AFError.MultipartEncodingFailureReason {
    var localizedDescription: String {
        switch self {
        case .bodyPartURLInvalid(let url):
            return "The URL provided is not a file URL: \(url)"
        case .bodyPartFilenameInvalid(let url):
            return "The URL provided does not have a valid filename: \(url)"
        case .bodyPartFileNotReachable(let url):
            return "The URL provided is not reachable: \(url)"
        case .bodyPartFileNotReachableWithError(let url, let error):
            return (
                "The system returned an error while checking the provided URL for " +
                "reachability.\nURL: \(url)\nError: \(error)"
            )
        case .bodyPartFileIsDirectory(let url):
            return "The URL provided is a directory: \(url)"
        case .bodyPartFileSizeNotAvailable(let url):
            return "Could not fetch the file size from the provided URL: \(url)"
        case .bodyPartFileSizeQueryFailedWithError(let url, let error):
            return (
                "The system returned an error while attempting to fetch the file size from the " +
                "provided URL.\nURL: \(url)\nError: \(error)"
            )
        case .bodyPartInputStreamCreationFailed(let url):
            return "Failed to create an InputStream for the provided URL: \(url)"
        case .outputStreamCreationFailed(let url):
            return "Failed to create an OutputStream for URL: \(url)"
        case .outputStreamFileAlreadyExists(let url):
            return "A file already exists at the provided URL: \(url)"
        case .outputStreamURLInvalid(let url):
            return "The provided OutputStream URL is invalid: \(url)"
        case .outputStreamWriteFailed(let error):
            return "OutputStream write failed with error: \(error)"
        case .inputStreamReadFailed(let error):
            return "InputStream read failed with error: \(error)"
        }
    }
}

extension AFError.ResponseSerializationFailureReason {
    var localizedDescription: String {
        switch self {
        case .inputDataNil:
            return "Response could not be serialized, input data was nil."
        case .inputDataNilOrZeroLength:
            return "Response could not be serialized, input data was nil or zero length."
        case .inputFileNil:
            return "Response could not be serialized, input file was nil."
        case .inputFileReadFailed(let url):
            return "Response could not be serialized, input file could not be read: \(url)."
        case .stringSerializationFailed(let encoding):
            return "String could not be serialized with encoding: \(encoding)."
        case .jsonSerializationFailed(let error):
            return "JSON could not be serialized because of error:\n\(error.localizedDescription)"
        case .propertyListSerializationFailed(let error):
            return "PropertyList could not be serialized because of error:\n\(error.localizedDescription)"
        }
    }
}

extension AFError.ResponseValidationFailureReason {
    var localizedDescription: String {
        switch self {
        case .dataFileNil:
            return "Response could not be validated, data file was nil."
        case .dataFileReadFailed(let url):
            return "Response could not be validated, data file could not be read: \(url)."
        case .missingContentType(let types):
            return (
                "Response Content-Type was missing and acceptable content types " +
                "(\(types.joined(separator: ","))) do not match \"*/*\"."
            )
        case .unacceptableContentType(let acceptableTypes, let responseType):
            return (
                "Response Content-Type \"\(responseType)\" does not match any acceptable types: " +
                "\(acceptableTypes.joined(separator: ","))."
            )
        case .unacceptableStatusCode(let code):
            return "Response status code was unacceptable: \(code)."
        }
    }
}

總結(jié)

通過閱讀AFError這篇代碼,給了我很大的震撼涨颜,在代碼的設(shè)計(jì)上庭瑰,可以參考這種設(shè)計(jì)方式弹灭。
由于知識水平有限穷吮,如有錯(cuò)誤,還望指出

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缠诅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乍迄,老刑警劉巖管引,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異就乓,居然都是意外死亡汉匙,警方通過查閱死者的電腦和手機(jī)拱烁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來噩翠,“玉大人戏自,你說我怎么就攤上這事伤锚∩帽剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵屯援,是天一觀的道長猛们。 經(jīng)常有香客問我,道長狞洋,這世上最難降的妖魔是什么弯淘? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吉懊,結(jié)果婚禮上庐橙,老公的妹妹穿的比我還像新娘。我一直安慰自己借嗽,他們只是感情好态鳖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恶导,像睡著了一般运沦。 火紅的嫁衣襯著肌膚如雪归敬。 梳的紋絲不亂的頭發(fā)上始赎,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天迹炼,我揣著相機(jī)與錄音,去河邊找鬼缤沦。 笑死虎韵,一個(gè)胖子當(dāng)著我的面吹牛易稠,可吹牛的內(nèi)容都是我干的缸废。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驶社,長吁一口氣:“原來是場噩夢啊……” “哼企量!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起亡电,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤届巩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后份乒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恕汇,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腕唧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘾英。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枣接。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缺谴,靈堂內(nèi)的尸體忽然破棺而出但惶,到底是詐尸還是另有隱情,我是刑警寧澤湿蛔,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布膀曾,位于F島的核電站,受9級特大地震影響阳啥,放射性物質(zhì)發(fā)生泄漏添谊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一察迟、第九天 我趴在偏房一處隱蔽的房頂上張望碉钠。 院中可真熱鬧,春花似錦卷拘、人聲如沸喊废。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽污筷。三九已至,卻和暖如春乍赫,著一層夾襖步出監(jiān)牢的瞬間瓣蛀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工雷厂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惋增,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓改鲫,卻偏偏與公主長得像诈皿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子像棘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

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