Alamofire 基础使用

作者: boundlessocean | 来源:发表于2020-07-09 17:42 被阅读0次

    目录

    一、发起请求
    • 1. 参数 <Parameter:Encodable>
    • 2. ParameterEncoder 参数编码器
      * 2.1 JSON参数编码器
      * 2.2 Form参数编码器
    • 3. HTTP Headers 请求头设置
    • 4. 响应处理
    二、下载文件
    • 下载Data
    • 下载到指定目录
    • 下载进度
    • 恢复下载
    三、上传文件
    • 上传 Data
    • 上传文件
    • 上传 Multipart Data
    • 上传进度

    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个两种编码器

    • JSONParameterEncoder
    • URLEncodedFormParameterEncoder
    2.1 JSON参数编码器

    JSONParameterEncoder 对应的 Content-Typeapplication/json

    • default
    • prettyPrinted 好看的格式打印
    • sortedKeys key排序
    /// 最终都是调用 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

    • Destination 决定参数存放的位置
      • methodDependent [.get, .head, .delete] 拼接URL ,默认使用此方式
      • queryString 拼接URL
      • httpBody
    /// httpBody 调用encode 将参数转为 Data 保存在 httpBody 中
    public func encode(_ value: Encodable) throws -> Data
    /// 拼接URL获得新的URL
    public func encode(_ value: Encodable) throws -> String {
        ...
        URLEncodedFormEncoder.encode(value)
        ...
    }
    
    • URLEncodedFormEncoder 决定了参数中不同类型的key,value编码方式
      • ArrayEncoding
        • brackets key[] 默认
        • noBrackets key
      • BoolEncoding
        • numeric true as 1, false as 0. 默认
        • literal true as "true", false as "false"
      • DataEncoding
        • deferredToData nil
        • base64 data.base64EncodedString() 默认
        • custom((Data) throws -> String)
      • 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).
      • KeyEncoding
        • useDefaultKeys 原样式 默认
        • convertToSnakeCase oneTwoThree becomes one_two_three
        • convertToKebabCase oneTwoThree becomes one-two-three.
        • capitalized oneTwoThree becomes OneTwoThree
        • uppercased oneTwoThree becomes ONETWOTHREE.
        • lowercased oneTwoThree becomes onetwothree
        • custom((String) -> String)
      • SpaceEncoding
        • percentEscaped string.replacingOccurrences(of: " ", with: "%20")
        • plusReplaced string.replacingOccurrences(of: " ", with: "+")
      • alphabetizeKeyValuePairs key/value 按照字母排序,默认true

    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序列化工具

    • 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)
            }
        }
    
    恢复下载
    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)
        }
    

    相关文章

      网友评论

        本文标题:Alamofire 基础使用

        本文链接:https://www.haomeiwen.com/subject/tqbscktx.html