PMHTTP 4.5.0

PMHTTP 4.5.0

测试已测试
语言语言 SwiftSwift
许可证 NOASSERTION
发布上次发布2019年11月
SPM支持 SPM

Lily Ballard 维护。



PMHTTP 4.5.0

PMHTTP

Version Platforms Languages License Carthage compatible CocoaPods

PMHTTP 是一个基于 URLSession 构建、以 Swift 为设计目标并保持与 Obj-C 兼容的 HTTP 框架。

我们认为 URLSession 很棒。但它是为 Obj-C 设计的,并且它不处理任何超越请求网络方面的内容。这意味着没有处理 JSON,甚至不提供 multipart/form-data 上传。PMHTTP 将网络交由 URLSession 处理,并提供所有其他功能。功能包括:

  • 请求可以定义解析处理程序,该处理程序将在与完成块异步地在单独的线程中执行,并且可以在解析和完成块期间取消请求,完成块将看到正确的结果。
  • 使用 PMJSON 提供一级 JSON 支持。
  • 结构化结果和高质量的错误;不再将 URLError.cancelled 视为网络错误。
  • 强类型结果。
  • 线程安全。
  • 智能缓存管理。.
  • 请求可以定义一次(包括解析处理器)并多次执行,就像 URLRequest 一样。
  • 可在失败请求安全的情况下配置自动重试失败请求。
  • 可配置基本 URL,允许在不更改构建请求的代码的情况下切换到预览版和生产环境。
  • 支持基本认证。
  • 支持 multipart/form-dataapplication/x-www-form-urlencoded 和 JSON 上传。
  • 无需使用方法交换即可提供内置请求模拟支持。
  • 没有东西使用主线程,即使是完成块也不例外,除非您明确要求。

PMHTTP 专门针对 Postmates 需要的 HTTP 功能而设计。这意味着具有注重 JSON 的高级 REST 支持。但还有一些功能它没有处理,我们可能在某个时候将其添加到项目中(查看问题)。欢迎提交拉取请求。

目录

使用方法

一个典型的GET请求看起来可能是这样的

// https://api.example.com/v1/search?query=%s
let task = HTTP.request(GET: "search", parameters: ["query": "cute cats"])
    .parseAsJSON(using: { (response, json) in
        return try JSON.map(json.getArray(), Cat.init(json:))
    })
    .performRequest(withCompletionQueue: .main) { task, result in
        switch result {
        case let .success(response, cats):
            // Do something with the Cats.
        case let .error(response, error):
            // Handle the error. This includes network errors, JSON parse errors,
            // and any error thrown by Cat.init(json:).
        case .canceled:
            // The task was canceled. Ignore or handle as appropriate.
        }
}
// task can be canceled and can be queried for its state
// and this can be done from any thread.

一个POST请求可能看起来是这样的

// https://api.example.com/v1/submit_cat
let task = HTTP.request(POST: "submit_cat", parameters: ["name": "Fluffles", "color": "tabby"])
    .parseAsJSON(using: { result in
        // POST parse blocks take a single `result` argument because 204 No Content is a valid
        // response. The `result` enum vends an optional `value` property, and has a
        // `getValue()` method that throws an error if the response was 204 No Content.
        return try SubmitCatResponse(json: result.getValue())
    })
    .performRequest(withCompletionQueue: .main) { task, result in
        switch result {
        case let .success(response, value):
            // value is a SubmitCatResponse.
        case let .error(response, error):
            // Handle the error. This could be a network error, a JSON parse error, or
            // any error thrown by SubmitCatResponse.init(json:).
        case .canceled:
            // The task was canceled.
        }
}

一个multipart/form-data上传可能看起来是这样的

// https://api.example.com/v1/submit_cat with photo
let req = HTTP.request(POST: "submit_cat", parameters: ["name": "Fluffles", "color": "tabby"])!
// We could add the image synchronously, but it's better to be asynchronous.
// Note: There is a convenience function to do this already, this is just an example.
req.addMultipartBody { upload in
    // This block executes on a background queue.
    if let data = UIImageJPEGRepresentation(catPhoto, 0.9) {
        upload.addMultipart(data: data, withName: "photo", mimeType: "image/jpeg")
    }
}
let task = req.parseAsJSON(using: { try SubmitCatResponse(json: $0.getValue()) })
    .performRequest(withCompletionQueue: .main) { task, result in
        // ...
}

设置

您可以在任何时候修改全局HTTPManager对象的属性,但为了使设置更简单,如果您的UIApplicationDelegateNSApplicationDelegate对象符合HTTPManagerConfigurable协议,则将在首次访问HTTP全局变量时要求配置HTTPManager。这看起来可能像这样

extension AppDelegate: HTTPManagerConfigurable {
    public func configure(httpManager: HTTPManager) {
        httpManager.environment = HTTPManager.Environment(string: /* ... */)
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 10
        // PMHTTP defines a default User-Agent but we can supply our own
        config.HTTPAdditionalHeaders = ["User-Agent": myUserAgent]
        httpManager.sessionConfiguration = config
        if let (username, apiKey) = getAPICredentials() {
            httpManager.defaultCredential = URLCredential(user: username, password: apiKey, persistence: .forSession)
        }
        httpManager.defaultRetryBehavior = HTTPManagerRetryBehavior.retryNetworkFailureOrServiceUnavailable(withStrategy: .retryTwiceWithDefaultDelay)
    }
}

详细设计

PMHTTP的设计考虑了以下6个目标

  • 尽可能像Swift一样,同时保留Obj-C兼容性。
  • 速度,重点是默认进行并发。
  • 在需要的地方保证线程安全。
  • 显式性和类型安全。例如,PMHTTP不会自动检测返回类型,但要求您声明期望的响应格式。
  • 正确性,包括避免意外的行为。
  • 使其易于添加新功能,例如自动重试和网络模拟。

HTTPManager

PMHTTP 的整体管理类是 HTTPManager。这是一个能够配置各种全局属性和创建新请求的类。如需,可以创建多个管理器,但一个全局实例在全局属性 HTTP 下提供(对于 Obj-C,这是 [HTTPManager defaultManager])。这个类上所有属性和方法都是完全线程安全的。

可以通过在你的应用代理上采用 HTTPManagerConfigurable 协议来配置共享的 HTTP 实例。该协议提供了一个方法,可以在首次访问 HTTP 属性时配置共享的 HTTPManager 对象。这种设计确保在使用之前共享实例已正确配置,即使它是在应用的正常入口点之前使用的(例如在某个类的 +load 方法内部)。但是请注意,此方法将在首次访问 HTTP 属性的任何线程上执行,因此应在任何线程上安全运行。

重要:共享的 HTTP 实例是为了应用使用而提供的便利。如果您正在编写使用 PMHTTP 的共享组件(例如,一个框架),您需要仔细考虑是否使用 HTTP 适当,或者是否应该使用 HTTPManager 的单独实例。只有在希望自动采用应用提供的任何配置(包括环境和默认凭证)时,使用 HTTP 才是适当的。

环境

HTTPManager 有一个类型为 HTTPManager.Environment 的属性 environment。环境是围绕 URL 的简单包装,表示请求应该使用的基 URL,如果请求不是使用绝对 URL 提交的。您可能想创建自己的扩展,看起来像这样:

extension HTTPManager.Environment {
    // @nonobjc works around "a declaration cannot be both 'final' and 'dynamic'" error.
    @nonobjc static let Production = HTTPManager.Environment(baseURL: productionURL)
    @nonobjc static let Staging = HTTPManager.Environment(baseURL: stagingURL)
}

环境还用于确定给定的请求是否应该采用在 HTTPManager 上配置的默认凭证。只有以环境为前缀的 URL 的请求将使用默认凭证。对于任何其他 URL 的请求,默认没有凭证,尽管可以始终向任何请求添加凭证。

请求

PMHTTP 中的请求是对象。在纯 Swift 世界中,它们是结构体/协议,但由于需要与 Obj-C 兼容,所以它们是对象。与 URLRequest 不同,PMHTTP 请求本质上是可以变的(所以它们类似于 NSMutableURLRequest)。它们也是 PMHTTP 中唯一公开的、不是线程安全的组件,尽管在没有任何线程修改请求的情况下,可以并发地访问请求(也就是说,从请求中读取值不会执行任何内部修改)。

请求被分为一个类的分层结构

  • HTTPManagerRequest - 根请求类型,它包含适用于所有请求的参数和方法。
    • HTTPManagerNetworkRequest - 所有请求的父类,这些请求没有解析处理程序。
      • HTTPManagerDataRequest - 用于没有解析处理的GET请求的类。
      • HTTPManagerActionRequest - 用于没有解析处理的POST/PUT/PATCH/DELETE请求的类或父类。
        • HTTPManagerUploadFormRequest - 用于没有解析处理的POST/PUT/PATCH请求的类,请求体为application/x-www-form-urlencodedmultipart/form-data
        • HTTPManagerUploadDataRequest - 用于没有解析处理的POST/PUT/PATCH请求的类,请求体由任意NSData组成。
        • HTTPManagerUploadJSONRequest - 用于没有解析处理的POST/PUT/PATCH请求的类,请求体由JSON值组成。
    • HTTPManagerParseRequest - 用于任何具有解析处理的请求的类。
    • HTTPManagerObjectParseRequest - 从Obj-C执行的请求,具有解析处理的类。与HTTPManagerParseRequest相似,但解析结果始终为AnyObject?

这种层次结构意味着每个类只能提供适用于该类所有请求的方法/属性。例如,只有HTTPManagerUploadFormRequest请求允许添加多部分体。

请求包含配置网络请求几乎所有方面的属性。尽管这些默认值来自HTTPManager对象,但这些默认值始终可以被覆盖。值得注意的是,一个属性为userInitiated,这是一个布尔属性,如果请求表示用户等待的一些操作,则应将其设置。将此属性设置为true会导致底层网络任务以高优先级执行,并导致所有后台队列处理都使用QOS_CLASS_USER_INITIATED

HTTPManagerUploadFormRequest提供了创建multipart/form-data请求的支持,这些请求可用于上传文件/图像。这些请求以流式格式实现,因此例如内存映射的NSData对象不会被复制到连续缓冲区中,从而允许您在不必担心内存使用的情况下上传文件。

HTTPManagerRequest符合NSCopying规范,因此如果需要,可以对任何请求进行复制。此外,在将解析处理程序附加到请求(因此将其转换为HTTPManagerParseRequest)时,会复制原始请求数据,因此对原始请求的后续修改不会影响解析请求。在执行请求时,也会复制请求数据,从而使请求可以在不影响执行的网络任务的情况下立即进行修改。

请求也设计得容易使用功能式链创建和执行,如上文中用法部分所示。

解析请求始终在后台队列上执行其解析处理程序,没有选项可以运行在特定的队列上(或主队列)。此约束既是为了鼓励后台解析,也是为了简单起见,因为可以通过跳过解析处理程序并在完成块中进行解析来随时在主队列上完成解析。

请求完成块默认也在后台队列上执行(对于有解析处理的请求,这将与执行解析处理程序相同的队列),尽管可以提供特定的队列,其中应运行完成块,例如主队列。

网络任务

执行请求返回一个类型为 HTTPManagerTask 的值。这个类是 PMHTTP 中与 URLSessionTask 等效的类,并且是完全线程安全的。它提供了检查请求当前状态的属性,包括访问底层的 URLSessionTask,并且提供了一个用于取消请求的 cancel() 方法。与 URLSessionTask.cancel() 不同,HTTPManagerTask.cancel() 可以在解析处理程序执行时取消请求,而不仅仅是取消网络部分。PMHTTP 保证,如果您在目标队列中执行 HTTPManagerTask.cancel(),并且在执行完成块之前,完成块将始终接收到 .canceled 的结果,即使它已经在执行 cancel() 之前完成了解析。这意味着,如果您将完成块的目标设置为 主队列,您可以确信取消的任务不会表现得像成功或失败。

URLSessionTask 类似,HTTPManagerTask 支持键值观察(尽管,与 URLSessionTask 一样,KVO 消息将在某些后台队列上发生)。

在没有自动重试的情况下,networkTask 属性值在整个任务生命周期中永远不会改变。如果已配置自动重试,则在请求重试时,networkTask 会改变,并广播任何相关的键值观察消息。

网络活动指示器

PMHTTP 提供了一个回调,您可以使用它来实现对全局网络活动指示器的支持。每个请求对象都有一个名为 affectsNetworkActivityIndicator 的属性(默认为 true),它控制由请求创建的任务是否会影响回调。回调本身通过将一个块赋给 HTTPManager.networkActivityHandler 来配置。此块在活动任务的数量更改时在主线程上运行。为了显示全局网络活动指示器,您可以按照以下方式配置

HTTPManager.networkActivityHandler = { active in
    UIApplication.sharedApplication().networkActivityIndicatorVisible = active > 0
}

失败请求的自动重试

PMHTTP 包括了对根据可配置策略自动重试失败请求的支持。默认重试策略可以通过 HTTPManager.defaultRetryBehavior 配置,可以在单个请求中使用 HTTPManagerRequest.retryBehavior 来覆盖。在 HTTPManagerRetryBehavior 上提供了一些常用的重试策略作为便捷方法,但也支持任何自定义策略。便捷策略实现了对各种 NSURLErrorDomain 错误的智能处理,例如,在遇到非暂时性错误(如 NSURLErrorAppTransportSecurityRequiresSecureConnection)时不会重试,或者在错误表明服务器从未收到请求时(例如 NSURLErrorCannotConnectToHost)将重试非幂等请求。默认情况下,重试是禁用的。

缓存处理

PMHTTP实现了对JSON响应的智能缓存处理。HTTP标准允许用户代理在响应不包含缓存头的情况下,根据其自愿缓存响应。然而,这种做法对于大多数REST API请求来说是不适当的,而且URLSession没有记录对这种响应的缓存策略。为了处理这种情况,PMHTTP会检查JSON响应中的适当缓存头,并明确阻止不包含适当缓存指令的响应被缓存。默认情况下,此行为仅应用于使用.parseAsJSON().parseAsJSON(using:).decodeAsJSON(_:)创建的请求,尽管可以根据每个请求进行覆盖(参见HTTPManagerRequest.defaultResponseCacheStoragePolicy)。值得注意的是,使用.parse(using:)创建的请求不使用此缓存策略,因为它会干扰图像请求的缓存。

模拟

PMHTTP内置了对网络请求的模拟支持。这是通过不进行交换(因此在App Store版本中也可以安全模拟请求)来完成的,并且它以一种仍然创建有效URLSessionTask的方式完成(因此任何检查HTTPManagerTask.networkTask的代码都将以预期的方式正常工作)。可以在HTTPManager整体上注册模拟,也可以独立地模拟单个请求(这样您就可以根据问题的更多方面来控制是否要模拟请求)。

测试

PMHTTP本身拥有一个全面的测试套件,涵盖Swift API中的几乎所有内容(目前未测试Objective-C特定API,见问题#7)。测试是在测试包中实现的自定义HTTP/1.1服务器上运行的,该服务器监听回环接口。这允许测试所有功能,而不需要依赖于外部服务,并确保测试速度非常快。HTTP/1.1服务器目前依赖于CocoaAsyncSocket,可以通过carthage bootstrap安装。Client of PMHTTP没有暴露这个依赖项,因为它是仅用于测试套件的。

HTTP/1.1服务器实现了我所认为的有用的大部分功能。它对PMHTTP本身的依赖只有少数(最值得注意的是,它使用HTTPManagerRequest.HTTPHeaders而不是重新实现功能),但是除此之外,它实际上可以被提取出来并用于任何需要HTTP/1.1服务器的其他地方。然而,由于这个服务器是为了测试目的而非实际生产而编写的,它并没有内置针对DOS攻击的缓解措施,除了拒绝大于5MiB的上传(例如,它不对头部长度施加任何限制,这些头部长度保留在内存中,并且连接时长没有超时机制)。此外,它本身也没有任何测试,除了在PMHTTP测试套件中使用时表现得符合预期之外。

要求

需要至少iOS 8、macOS 10.10、watchOS 2.0或tvOS 9.0。

安装

安装后,您可以通过在您的代码中添加import PMHTTP来使用此工具。

使用Carthage安装

要使用Carthage进行安装,请在您的Cartfile中添加以下内容:

github "postmates/PMHTTP" ~> 4.0

此版本支持Swift 4.0。对于Swift 3.x,您可以使用

github "postmates/PMHTTP" ~> 3.0

使用CocoaPods安装

要使用CocoaPods进行安装,请在您的Podfile中添加以下内容:

pod "PMHTTP", "~> 4.0"

此版本支持Swift 4.0。对于Swift 3.x,您可以使用

pod "PMHTTP", "~> 3.0"

许可证

许可协议为以下之一:

贡献

除非您明确声明,否则您提交的任何旨在包含在本作品中的贡献都应按照以上方式双授权,没有额外的条款或条件。

版本历史

v4.5.0 (2019-11-27)

  • 为创建具有 NSData 但没有显式 contentType 的上传请求添加了 Obj-C 便利函数(#65)。
  • 修复了 Obj-C 的 -setValue:forHeaderField:-setValue:forDefaultHeaderField: 方法,以接受可选值(#67)。
  • 添加了 HTTPManagerRetryBehavior.init(any:) 以组合多个重试行为(#69)。
  • 添加了 HTTPManagerRequest.HTTPHeaders 的方法 init(minimumCapacity:)reserveCapacity(_:) 以及属性 capacity#66)。

v4.4.3 (2019-11-14)

  • 除支持 PMJSON 3.x 之外,现在还支持 CocoaPods 中的 PMJSON 4.x。由于 Carthage 不支持这种版本范围,因此现在仅设置为 PMJSON 4.x。

v4.4.2 (2019-08-13)

  • 修复了与已弃用的 HTTPManagerObjectParseRequest.credential 属性相关的错误,其中将值赋给属性不会起作用。

v4.4.1(2019-04-24)

v4.4.0(2019-04-23)

  • 修复了解析图像时传递错误的类型标识提示值的bug,导致控制台记录警告(#62)。
  • HTTPManagerError上添加计算属性,便于访问关联值(例如.response.body等)。
  • 添加计算属性HTTPManagerError.statusCode,返回错误的失败状态码,或对于.unexpectedContentType返回nil#60)。
  • 添加Obj-C函数PMHTTPErrorGetStatusCode(),返回错误的失败状态码,或对于PMHTTPErrorUnexpectedContentType或非PMHTTP错误返回nil#60)。
  • 提供PMHTTPStatusCodeErrorKey用户信息键,用于更多错误类型(#59)。
  • 添加计算属性URLResponse.isUnmockedInterceptedRequest,可用于测试响应是否来自未安装模拟器拦截的请求(#46)。

v4.3.3(2019-04-07)

  • 更新PMHTTPErrorIsFailedResponse以处理除了PMHTTPErrorFailedResponsePMHTTPErrorUnauthorized之外的PMHTTPErrorUnexpectedNoContentPMHTTPErrorUnexpectedRedirect
  • 修复Xcode 10.2引入的警告。

v4.3.2(2018-11-14)

  • 修复了从 URL 构造的请求不继承环境默认设置(例如认证、头部等)的问题(#52)。

v4.3.1 (2018-08-01)

  • HTTPManagerRequest 添加了用于查询和设置协议属性的 URLProtocol 方法重载(#43)。

v4.3.0 (2018-07-26)

  • 暴露 HTTPManagerTask.userInitiated 为一个公开属性(#42)。
  • HTTPManager.MetricsCallback 回调添加另一个参数。为了保持向后兼容性,旧的初始化器和属性已被弃用,并添加了一个新的初始化器和属性,名称不同(#41)。

v4.2.0 (2018-07-10)

  • application/x-www-form-urlencoded 体和查询字符串编码更多的字符。值得一提的是,分号(;)现在将被百分号编码,因为一些服务器将其视为分隔符。
  • 优化了任务度量收集,以便如果 metricsCallbacknil,则不收集度量(#37)。
  • 扩展了内置的重试行为,以支持自定义策略(#35)。
  • 添加了与 URLRequest 属性 mainDocumentURLhttpShouldHandleCookies 对应的 HTTPManagerRequest 属性(#40)。

v4.1.1 (2018-06-21)

  • 添加了 HTTPHeaders.merge(_:uniquingKeysWith:)HTTPHeaders.merging(_:uniquingKeysWith:)
  • 弃用 HTTPHeaders.append(contentsOf:)
  • 在调用 HTTPManagerRequest.setDefaultEnvironmentalProperties() 时合并标题字段,在冲突情况下优先考虑现有的请求标题字段。

版本 4.1.0 (2018-06-15)

  • 在没有设置环境的情况下,支持模拟相对 URL。
  • 将默认模拟延迟缩短到 10ms。
  • 在 Objective-C 中使 HTTPManagerRequest.headerFields 可变。
  • 添加 HTTPManager.defaultHeaderFields,它定义要附加到请求的默认头部字段,类似于 defaultAuth,仅适用于当前环境内的请求。
  • HTTPManagerRequest.HTTPHeaders 宣告符合 Equatable 标准。
  • 修复使用延迟的multipart正文和 serverRequiresContentLength 绑定时产生的致命错误。
  • 添加 HTTPManager.metricsCallback 以收集与 HTTPManager 相关的所有任务指标(URLSessionTaskMetrics)。

版本 4.0.1 (2018-05-17)

  • 修复 <PMHTTP/PMHTTP.h>,以便可以从 Objective-C++ 代码中导入。

版本 4.0.0 (2018-02-23)

  • 转换为 Swift 4。
  • 添加方法 HTTPManagerParseRequest.map(_:)
  • 添加方法 HTTPManagerDataRequest.decodeAsJSON(_:with:options:)HTTPManagerActionRequest.decodeAsJSON(_:with:options:)

版本 3.0.5 (2017-09-11)

  • 扩展 HTTPAuth 以支持处理 403 禁止错误。

版本 3.0.4 (2017-09-05)

  • 支持 Swift 3.2。
  • preparedURLRequest 中正确处理 serverRequiresContentLength

v3.0.3 (2017-08-18)

  • 将具有URL参数的请求创建方法添加重载,这些重载返回一个非可选请求。
  • 添加新的属性 HTTPManagerRequest.serverRequiresContentLength。这将禁用流式体支持(用于JSON和multipart/mixed),并同步处理体,以便可以向服务器提供"Content-Length"头。还有一个对应的 HTTPManager.defaultServerRequiresContentLength 属性。
  • 添加方法 HTTPManagerRequest.setDefaultEnvironmentalProperties(),该方法设置属性到HTTPManager定义的默认值,否则只有当请求的路径匹配环境时才会设置。这主要用于使用绝对路径构建的请求(例如HTTP.request(GET: "/foo")),应该仍然使用环境默认值。目前,此方法仅设置authserverRequiresContentLength

v3.0.2 (2017-05-01)

  • @discardableResult添加到Objective-C中的-performRequest…方法。

v3.0.1 (2017-03-28)

  • 修复Xcode 8.3兼容性问题。

v3.0.0 (2017-02-27)

  • 在重试任务时保留网络任务优先级。
  • 添加便利的Objective-C函数PMHTTPErrorIsFailedResponse,以轻松测试PMHTTP错误。
  • HTTPManagerDataRequestHTTPManagerActionRequest添加方法 .parseAsImage(scale:).parseAsImage(scale:using:)
  • 当会话被重置时,取消任何创建但未恢复的任务。
  • 确保在完成队列或创建任务的线程上始终释放完成块。以前,存在一个非常微妙的竞争条件,意味着完成块可能会在URLSession的代理队列上释放。这仅在您的完成块捕获值且deinit关心当前线程的情况下有意义。
  • 扩展作为参数传递的字典、数组和集合。字典将产生形如"foo[bar]"的键,数组集合则将键重复多次使用(例如:"foo=bar&foo=qux")。扩展是递归的。扩展的字典和集合的值顺序由实现定义。如果你想要使用"array[]"语法,请将"[]"放在键中本身。有关更多详细信息,请参阅文档注释。请注意,此行为与AFNetworking稍有不同。
  • 同时扩展参数中的嵌套URLQueryItem。结果参数使用字典语法("foo[bar]")。
  • 更改接收处理程序的Obj-C解析方法的类型签名,使错误参数非可选。
  • 提供用于会话级身份验证挑战的回调。这可以用于使用如TrustKit之类的工具实现SSL pinning。
  • 修复重试任务时的内存泄漏。
  • 重新设计身份验证工作方式。已用defaultAuthauth替换了defaultCredentialcredential属性,使用全新的协议HTTPAuth。提供基本身份验证的实现为HTTPBasicAuth对象。这种新的身份验证机制旨在允许OAuth2风格的刷新,并提供了辅助类HTTPRefreshableAuth以实现可刷新的身份验证。

v2.0.1 (2017-01-05)

  • 修复CocoaPods podspec中PMJSON的依赖。

v2.0.0 (2017-01-03)

  • 支持除了application/json之外的text/json
  • 添加两项方便的方法,用于将UIImage作为PNG或JPEG数据上传。
  • PMHTTPResult添加objcError属性。
  • HTTPManagerTaskResult上的objcError改为Error?而不是NSError?
  • 修复单元测试与Xcode 8.1的兼容性。
  • parseAsJSON()parseAsJSON(with:)添加可选的options参数。
  • HTTPManagerUploadFormRequest添加withMultipartBody(using:)
  • parse(with:)parseAsJSON(options:with:)addMultipartBody(with:)重命名为使用using:作为参数名,这更符合Swift 3 Foundation的命名约定。

v1.0.4 (2016-10-20)

  • 添加更多的Obj-C请求构建器。
  • 修复查询字符串和application/x-www-form-urlencoded体中+字符的编码。

v1.0.3 (2016-09-23)

  • 修复 HTTPManager.parsedDateHeader(from:) 的 Objective-C 名称。

v1.0.2 (2016-09-22)

  • 添加 Swift 3 API 变更的修正代码。

v1.0.1 (2016-09-12)

  • 采用 CustomNSError 并弃用 NSError 桥接方法。
  • 适当时在 dispatch queues 添加 autoreleasepool。
  • 修复 CocoaPods 支持。

v1.0.0 (2016-09-09)

  • 支持 Swift 3.0。

v0.9.3 (2016-09-09)

  • 修复针对 tvOS 构建的问题。

v0.9.2 (2016-09-09)

  • 支持 Swift 2.3。

v0.9.1 (2016-08-17)

  • 将 Source 文件夹重命名为 Sources。
  • CocoaPods 支持。

v0.9 (2016-08-05)

首次发布。