PMHTTP
PMHTTP 是一个基于 URLSession
构建、以 Swift 为设计目标并保持与 Obj-C 兼容的 HTTP 框架。
我们认为 URLSession
很棒。但它是为 Obj-C 设计的,并且它不处理任何超越请求网络方面的内容。这意味着没有处理 JSON,甚至不提供 multipart/form-data
上传。PMHTTP 将网络交由 URLSession
处理,并提供所有其他功能。功能包括:
- 请求可以定义解析处理程序,该处理程序将在与完成块异步地在单独的线程中执行,并且可以在解析和完成块期间取消请求,完成块将看到正确的结果。
- 使用 PMJSON 提供一级 JSON 支持。
- 结构化结果和高质量的错误;不再将
URLError.cancelled
视为网络错误。 - 强类型结果。
- 线程安全。
- 智能缓存管理。.
- 请求可以定义一次(包括解析处理器)并多次执行,就像
URLRequest
一样。 - 可在失败请求安全的情况下配置自动重试失败请求。
- 可配置基本 URL,允许在不更改构建请求的代码的情况下切换到预览版和生产环境。
- 支持基本认证。
- 支持
multipart/form-data
、application/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
对象的属性,但为了使设置更简单,如果您的UIApplicationDelegate
或NSApplicationDelegate
对象符合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-urlencoded
或multipart/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"
许可证
许可协议为以下之一:
- Apache许可证,版本2.0(《LICENSE-APACHE`或https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(《LICENSE-MIT`或https://open-source.org.cn/licenses/MIT),任选其一。
贡献
除非您明确声明,否则您提交的任何旨在包含在本作品中的贡献都应按照以上方式双授权,没有额外的条款或条件。
版本历史
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)
- 针对Swift版本解决CocoaPods的bug(CocoaPods/CocoaPods#8635)。
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
以处理除了PMHTTPErrorFailedResponse
和PMHTTPErrorUnauthorized
之外的PMHTTPErrorUnexpectedNoContent
和PMHTTPErrorUnexpectedRedirect
。 - 修复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
体和查询字符串编码更多的字符。值得一提的是,分号(;)现在将被百分号编码,因为一些服务器将其视为分隔符。 - 优化了任务度量收集,以便如果
metricsCallback
是nil
,则不收集度量(#37)。 - 扩展了内置的重试行为,以支持自定义策略(#35)。
- 添加了与
URLRequest
属性mainDocumentURL
和httpShouldHandleCookies
对应的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")
),应该仍然使用环境默认值。目前,此方法仅设置auth
和serverRequiresContentLength
。
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错误。 - 向
HTTPManagerDataRequest
和HTTPManagerActionRequest
添加方法.parseAsImage(scale:)
和.parseAsImage(scale:using:)
。 - 当会话被重置时,取消任何创建但未恢复的任务。
- 确保在完成队列或创建任务的线程上始终释放完成块。以前,存在一个非常微妙的竞争条件,意味着完成块可能会在
URLSession
的代理队列上释放。这仅在您的完成块捕获值且deinit
关心当前线程的情况下有意义。 - 扩展作为参数传递的字典、数组和集合。字典将产生形如
"foo[bar]"
的键,数组集合则将键重复多次使用(例如:"foo=bar&foo=qux"
)。扩展是递归的。扩展的字典和集合的值顺序由实现定义。如果你想要使用"array[]"
语法,请将"[]"
放在键中本身。有关更多详细信息,请参阅文档注释。请注意,此行为与AFNetworking稍有不同。 - 同时扩展参数中的嵌套
URLQueryItem
。结果参数使用字典语法("foo[bar]"
)。 - 更改接收处理程序的Obj-C解析方法的类型签名,使错误参数非可选。
- 提供用于会话级身份验证挑战的回调。这可以用于使用如TrustKit之类的工具实现SSL pinning。
- 修复重试任务时的内存泄漏。
- 重新设计身份验证工作方式。已用
defaultAuth
和auth
替换了defaultCredential
和credential
属性,使用全新的协议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)
首次发布。