iOS之Alamofire 初探

2,183 阅读2分钟

简介:

Alamofire是使用Swift语言开发的网络库,它和AFNetworking是同一班子的开发团队。

Alamofire使用链式编程实现的。具有简洁的语法,良好的性能和优秀的可读性等特点。

Alamofire,本质上是基于NSURLSession进行封装的,其核心是URLSession和URLSessionTask子类。其早期版本使用Alamofire.request(),5.0之后使用AF.request()

一、Alamofire 基本使用

我们通过一个例子来了解:

struct JsonArray: Decodable {
    let channels: [Json]
}
struct Json: Decodable {

    let abbr_en: String
    let channel_id: String?
    let name: String
    let name_en: String
    let seq_id: Int
}
AF.request(urlString)
            .responseDecodable(of: JsonArray.self) { response in
                print(response)
            }

短短几行代码,我们就写好一个请求网络了。

image.png 如果我们修改代码:

AF.request(URL(string: urlString)!)
            .responseDecodable(of: JsonArray.self) { response in
                print(response)
            }

传入URL类型的url方法也正常进行。为什么呢,我们进入源码查看一下:

    open func request(_ convertible: URLConvertible,
                      method: HTTPMethod = .get,
                      parameters: Parameters? = nil,
                      encoding: ParameterEncoding = URLEncoding.default,
                      headers: HTTPHeaders? = nil,
                      interceptor: RequestInterceptor? = nil,
                      requestModifier: RequestModifier? = nil) -> DataRequest {
        let convertible = RequestConvertible(url: convertible,
                                             method: method,
                                             parameters: parameters,
                                             encoding: encoding,
                                             headers: headers,
                                             requestModifier: requestModifier)
        return request(convertible, interceptor: interceptor)
    }

看到了convertible: URLConvertible ,遵循了URLConvertible协议。 image.png 在来看一个问题:

为什么可以用AF.request呢?

image.png 我们查看代码发现,AF直接就是Session.default。所以Alamofire就是基于NSURLSession进行封装的。

Alamofire支持4种返回响应处理方式:Data、String、 JSON、自定义类型。下面分别举例说明

        //Data示例
        let url = "https://httpny.org/get"
        AF.request(url).responseData { response in
            switch response.result {
                case let .success(data):
                print("data:\(String(describing: data))")
                case let .failure(error):
                print(error)
            }
        }
        //String示例
        AF.request(url).responseString { response in
            switch response.result {
                case let .success(data):
                print("data:\(String(describing: data))")
                case let .failure(error):
                print(error)
            }
        }
        //JSON示例
        AF.request(url).responseJSON { response in
            switch response.result {
                case let .success(data):
                print("data:\(String(describing: data))")
                case let .failure(error):
                print(error)
            }
        }
        //自定义格式示例
        AF.request(url).responseDecodable(of: PersonResponse.self) { response in
            switch response.result {
                case let .success(data):
                print("data:\(String(describing: data))")
                case let .failure(error):
                print(error)
            }
        }

一般情况下使用的都是自定义类型of: PersonResponse.self

1.POST 提交例子

struct Login: Encodable {
    let email:String
    let password:String
}

let login = Login(email: "aaa", password: "bbb")
AF.request("https://httpny.org/post",
               method: .post,
               parameters: login,
               encoder: JSONParameterEncoder.default)
    .response { response in
        debugPrint(response)
}

2. 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://httpny.org/headers", headers: headers).responseJSON { response in
    debugPrint(response)
}

3. 下载文件

下载到指定目录:

let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
AF.download("https://httpny.org/image/png", to: destination).response { response in
    debugPrint(response)

    if response.error == nil, let imagePath = response.fileURL?.path {
        let image = UIImage(contentsOfFile: imagePath)
    }
}

下载恢复:

var resumeData: Data!

let download = AF.download("https://httpny.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)
    }
}

4. 上传文件

上传进度:

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)
    }