swift专栏基础应用Swift

Alamofire 基础使用

2020-07-09  本文已影响0人  boundlessocean

目录

一、发起请求
二、下载文件
三、上传文件

Alamofire是基于Apple提供的 URL加载系统,核心是URLSession和URLSessionTask子类。 早期版本使用Alamofire.request(),5.0版本使用AF命名,AF引用Session.default

一、发起请求

简单示例:

AF.request("https://httpbin.org/get").response { response in
    debugPrint(response)
}

两个发起请求的API

/// 1. 配置请求组成 URLRequest、本篇主要内容(基础用法)
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. 参数 <Parameter:Encodable>

只要参数遵循Encodable协议,那么最终ParameterEncoder都会把Parameter encode成需要的数据类型

举个例子

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 参数编码器

参数编码器 最终决定了参数在请求中的存在的样式

我们通过参数编码器把参数编码成服务器需要的数据类型

Alamofire提供了2个两种编码器

2.1 JSON参数编码器

JSONParameterEncoder 对应的 Content-Typeapplication/json

/// 最终都是调用 encode 将参数转为 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参数编码器

URLEncodedFormParameterEncoder 对应的 Content-Type

application/x-www-form-urlencoded; charset=utf-8

Form参数编码器只有一个默认的编码器default

/// httpBody 调用encode 将参数转为 Data 保存在 httpBody 中
public func encode(_ value: Encodable) throws -> Data
/// 拼接URL获得新的URL
public func encode(_ value: Encodable) throws -> String {
    ...
    URLEncodedFormEncoder.encode(value)
    ...
}

3. HTTP Headers 请求头设置

​ 提供3种初始化方式

/// 1. 无参构造
public init() {}

/// 通过以下方式添加值
func add(name: String, value: String)
func add(_ header: HTTPHeader)
/// 2. 通过 HTTPHeader 数组构造
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 构造
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. 响应处理

Alamofire 提供了4种 Response序列化工具

// 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)")
}
// 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)")
}
// 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)")
}
// 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)")
}
// 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)
        }
    }
恢复下载
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)
    }
上一篇下一篇

猜你喜欢

热点阅读