- 这段代码就是对
ParameterEncoding
协议的三种不同实现,分别是URLEncoding
,JSONEncoding
,PropertyListEncoding
。以及定义了Parameters
类型
/// A dictionary of parameters to apply to a `URLRequest`.
public typealias Parameters = [String: Any]
/// A type used to define how a set of parameters are applied to a `URLRequest`.
public protocol ParameterEncoding {
/// Creates a URL request by encoding parameters and applying them onto an existing request.
///
/// - parameter urlRequest: The request to have parameters applied.
/// - parameter parameters: The parameters to apply.
///
/// - throws: An `AFError.parameterEncodingFailed` error if encoding fails.
///
/// - returns: The encoded request.
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}
-
ParameterEncoding
协议定义了一个encode
方法,返回encoded request
URLEncoding
定义了四个静态参数,用于快速获取对应的类型。default
和methodDependent
都返回默认值
public enum Destination {
case methodDependent, queryString, httpBody
}
// MARK: Properties
/// Returns a default `URLEncoding` instance.
public static var `default`: URLEncoding { return URLEncoding() }
/// Returns a `URLEncoding` instance with a `.methodDependent` destination.
public static var methodDependent: URLEncoding { return URLEncoding() }
/// Returns a `URLEncoding` instance with a `.queryString` destination.
public static var queryString: URLEncoding { return URLEncoding(destination: .queryString) }
/// Returns a `URLEncoding` instance with an `.httpBody` destination.
public static var httpBody: URLEncoding { return URLEncoding(destination: .httpBody) }
URLEncoding
的encode
方法:
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
guard let url = urlRequest.url else {
throw AFError.parameterEncodingFailed(reason: .missingURL)
}
if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
urlComponents.percentEncodedQuery = percentEncodedQuery
urlRequest.url = urlComponents.url
}
} else {
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
}
return urlRequest
}
- 检查
urlRequest
能否正常生成,parameters
不能为空。 - 当
destination
为.queryString
,或者method
是.get, .head, .delete
类型时,如果parameter
不为空把里面的键值对传化为“xx=xx&yy=yy"的格式然后赋值给URLComponents.percentEncodedQuery
最后urlRequest.url = urlComponents.url
。另一种情况直接把query返回的字符串赋给httpBody
["a":"apple","b":"book","c":["conent","capacity","contact"],
"d":["4":"dose","5":"dairy"],"e":true,"f":12]
应该转化成:
"a=apple&b=book&c[]=conent&c[]=capacity
&c[]=contact&d[4]=dose&d[5]=dairy&e=1&f=12"
但是实际转化过程中使用了
public func escape(_ string: String) -> String 方法
所以最终结果是如下:
"a=apple&b=book&c%5B%5D=conent&c%5B%5D=capacity
&c%5B%5D=contact&d%5B4%5D=dose&d%5B5%5D=dairy&e=1&f=12"
其中的“[”,"]"变成了“%5B”,"%5D"
JSONEncoding
JSONEncoding
有两个encode
方法,除了ParameterEncoding
的添加了一个encode(_ urlRequest:,withJSONObject jsonObject:Any? = nil) -> URLRequest
,两个方法的实现基本相似并且很简单
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
do {
let data = try JSONSerialization.data(withJSONObject: parameters, 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))
}
return urlRequest
}
PropertyListEncoding
很少用到
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var urlRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return urlRequest }
do {
let data = try PropertyListSerialization.data(
fromPropertyList: parameters,
format: format,
options: options
)
if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
urlRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type")
}
urlRequest.httpBody = data
} catch {
throw AFError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error))
}
return urlRequest
}
}