目錄
一簇秒、發(fā)起請求
- 1. 參數(shù)
<Parameter:Encodable>
- 2. ParameterEncoder 參數(shù)編碼器
* 2.1 JSON參數(shù)編碼器
* 2.2 Form參數(shù)編碼器 - 3. HTTP Headers 請求頭設(shè)置
- 4. 響應(yīng)處理
二、下載文件
- 下載Data
- 下載到指定目錄
- 下載進度
- 恢復(fù)下載
三秀鞭、上傳文件
- 上傳 Data
- 上傳文件
- 上傳 Multipart Data
- 上傳進度
Alamofire是基于Apple提供的 URL加載系統(tǒng)趋观,核心是URLSession和URLSessionTask子類。 早期版本使用Alamofire.request()锋边,5.0版本使用AF命名皱坛,AF引用Session.default
一、發(fā)起請求
簡單示例:
AF.request("https://httpbin.org/get").response { response in
debugPrint(response)
}
兩個發(fā)起請求的API
/// 1. 配置請求組成 URLRequest豆巨、本篇主要內(nèi)容(基礎(chǔ)用法)
open func request<Parameters: Encodable>(_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest
/// 2. 直接請求組裝好的 URLRequest (高級用法)
open func request(_ urlRequest: URLRequestConvertible,
interceptor: RequestInterceptor? = nil) -> DataRequest
1. 參數(shù) <Parameter:Encodable>
只要參數(shù)遵循Encodable
協(xié)議麸恍,那么最終ParameterEncoder
都會把Parameter
encode
成需要的數(shù)據(jù)類型
舉個例子
struct Login: Encodable {
let email:String
let password:String
}
let login = Login(email: "aaa", password: "bbb")
AF.request("https://httpbin.org/post",
method: .post,
parameters: login,
encoder: JSONParameterEncoder.default)
.response { response in
debugPrint(response)
}
2. ParameterEncoder 參數(shù)編碼器
參數(shù)編碼器 最終決定了參數(shù)在請求中的存在的樣式
我們通過參數(shù)編碼器把參數(shù)編碼成服務(wù)器需要的數(shù)據(jù)類型
Alamofire提供了2個兩種編碼器
JSONParameterEncoder
URLEncodedFormParameterEncoder
2.1 JSON參數(shù)編碼器
JSONParameterEncoder
對應(yīng)的 Content-Type
為 application/json
default
-
prettyPrinted
好看的格式打印 -
sortedKeys
key排序
/// 最終都是調(diào)用 encode 將參數(shù)轉(zhuǎn)為 Data 保存在 httpBody 中
open func encode<T>(_ value: T) throws -> Data where T : Encodable
let data = try encoder.encode(parameters)
request.httpBody = data
2.2 Form參數(shù)編碼器
URLEncodedFormParameterEncoder
對應(yīng)的 Content-Type
為
application/x-www-form-urlencoded; charset=utf-8
Form參數(shù)編碼器只有一個默認的編碼器default
- Destination 決定參數(shù)存放的位置
- methodDependent [.get, .head, .delete] 拼接URL ,默認使用此方式
- queryString 拼接URL
- httpBody
/// httpBody 調(diào)用encode 將參數(shù)轉(zhuǎn)為 Data 保存在 httpBody 中
public func encode(_ value: Encodable) throws -> Data
/// 拼接URL獲得新的URL
public func encode(_ value: Encodable) throws -> String {
...
URLEncodedFormEncoder.encode(value)
...
}
- URLEncodedFormEncoder 決定了參數(shù)中不同類型的key,value編碼方式
- ArrayEncoding
- brackets
key[]
默認 - noBrackets
key
- brackets
- BoolEncoding
- numeric
true
as1
,false
as0
. 默認 - literal
true
as "true",false
as "false"
- numeric
- DataEncoding
- deferredToData
nil
- base64
data.base64EncodedString()
默認 - custom((Data) throws -> String)
- deferredToData
- DateEncoding
- deferredToDate
nil
默認 - secondsSince1970
String(date.timeIntervalSince1970)
- millisecondsSince1970
String(date.timeIntervalSince1970 * 1000.0)
- iso8601 ISO8601DateFormatter()
- formatted(DateFormatter)
formatter.string(from: date)
- custom((Date) throws -> String).
- deferredToDate
- KeyEncoding
- useDefaultKeys 原樣式 默認
- convertToSnakeCase
oneTwoThree
becomesone_two_three
- convertToKebabCase
oneTwoThree
becomesone-two-three
. - capitalized
oneTwoThree
becomesOneTwoThree
- uppercased
oneTwoThree
becomesONETWOTHREE
. - lowercased
oneTwoThree
becomesonetwothree
- custom((String) -> String)
- SpaceEncoding
- percentEscaped
string.replacingOccurrences(of: " ", with: "%20")
- plusReplaced
string.replacingOccurrences(of: " ", with: "+")
- percentEscaped
- alphabetizeKeyValuePairs key/value 按照字母排序搀矫,默認true
- ArrayEncoding
3. HTTP Headers 請求頭設(shè)置
提供3種初始化方式
/// 1. 無參構(gòu)造
public init() {}
/// 通過以下方式添加值
func add(name: String, value: String)
func add(_ header: HTTPHeader)
/// 2. 通過 HTTPHeader 數(shù)組構(gòu)造
public init(_ headers: [HTTPHeader])
let headers: HTTPHeaders = [
HTTPHeader(name: "Authorization", value: "Basic VXNlcm5hbWU6UGFzc3dvcmQ="),
HTTPHeader(name: "Accept", value: "application/json")
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
/// 3. 通過key/value 構(gòu)造
public init(_ dictionary: [String: String])
let headers: HTTPHeaders = [
"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
"Accept": "application/json"
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
4. 響應(yīng)處理
Alamofire 提供了4種 Response
序列化工具
- DataResponseSerializer 解析為Data
// Response Handler - Unserialized Response
func response(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self
// Response Data Handler - Serialized into Data
func responseData(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<Data>) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseData { response in
debugPrint("Response: \(response)")
}
- StringResponseSerializer 解析為String
// Response String Handler - Serialized into String
func responseString(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
encoding: String.Encoding? = nil,
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = StringResponseSerializer.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseString { response in
debugPrint("Response: \(response)")
}
- JSONResponseSerializer 解析為JSON
// Response JSON Handler - Serialized into Any Using JSONSerialization
func responseJSON(queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor,
emptyResponseCodes: Set<Int> = JSONResponseSerializer.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = JSONResponseSerializer.defaultEmptyRequestMethods,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse<Any>) -> Void) -> Self
//示例
AF.request("https://httpbin.org/get").responseJSON { response in
debugPrint("Response: \(response)")
}
- DecodableResponseSerializer 解析為指定類型<T: Decodable>
// Response Decodable Handler - Serialized into Decodable Type
func responseDecodable<T: Decodable>(of type: T.Type = T.self,
queue: DispatchQueue = .main,
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<T>.defaultDataPreprocessor,
decoder: DataDecoder = JSONDecoder(),
emptyResponseCodes: Set<Int> = DecodableResponseSerializer<T>.defaultEmptyResponseCodes,
emptyRequestMethods: Set<HTTPMethod> = DecodableResponseSerializer<T>.defaultEmptyRequestMethods,
completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self
//示例
struct HTTPBinResponse: Decodable { let url: String }
AF.request("https://httpbin.org/get").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint("Response: \(response)")
}
- DataResponseSerializerProtocol 使用自定義解析 Serializer: DataResponseSerializerProtocol
// Response Serializer Handler - Serialize using the passed Serializer
func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void) -> Self
//示例 自定義解析為 Dictionary
public final class DictionaryResponseSerializer: ResponseSerializer {
public func serialize(request: URLRequest?,
response: HTTPURLResponse?,
data: Data?, error: Error?) throws -> Dictionary<String, Any> {
guard error == nil else { throw error! }
guard let data = data, !data.isEmpty else {
guard emptyResponseAllowed(forRequest: request, response: response) else {
throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
}
return [:]
}
do {
return try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.fragmentsAllowed) as! Dictionary<String, Any>
} catch {
throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))
}
}
}
AF.request("https://httpbin.org/get").response(responseSerializer: DictionaryResponseSerializer()) { (response) in
switch response.result {
case .success(let bin):
debugPrint(bin)
case .failure(let error):
debugPrint(error)
}
}
二、下載文件
下載Data
AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
下載到指定目錄
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
AF.download("https://httpbin.org/image/png", to: destination).response { response in
debugPrint(response)
if response.error == nil, let imagePath = response.fileURL?.path {
let image = UIImage(contentsOfFile: imagePath)
}
}
下載進度
AF.download("https://httpbin.org/image/png")
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
恢復(fù)下載
var resumeData: Data!
let download = AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
// download.cancel(producingResumeData: true) // Makes resumeData available in response only.
download.cancel { data in
resumeData = data
}
AF.download(resumingWith: resumeData).responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
三刻肄、上傳文件
上傳 Data
let data = Data("data".utf8)
AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳文件
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳 Multipart Data
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳進度
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post")
.uploadProgress { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
最后封裝了一個基于Moya&RXSwift&HandyJSON的網(wǎng)絡(luò)庫使用:PomeloNet