Swift3.0 Alamofire初级应用

来源:互联网 发布:mac加密文件夹弹出 编辑:程序博客网 时间:2024/06/05 11:20

 序:做过iOS开发的人肯定都知道AFN,现在Swift逐渐流行AFN团队又用Swift写了Alamofire。从头开始学习一下,看看新的Alamofire有什么性能的优化和不同。


大家都知道Alamofire是一个HTTP的网络封装库,首先我们肯定要先知道用Alamofire我们可以干什么。


功能特点


1、请求连接,处理接受不同类型的返回

2、 URL / JSON / plist 参数编码

3、上传 File / Data / Stream / MultipartFormData

4、用请求或者恢复数据下载文件

5、身份认证和url凭证

6、HTTP 返回验证

7、上传或者下载进程显示

8、cURL命令输出

9、动态适应和重试请求

10、TLS证书和公钥锁

11、网络是否可用判断

12、完整的单元检测


组件库

  • AlamofireImage 
  • AlamofireNetworkActivityIndicator 

环境要求

  • iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 8.1+
  • Swift 3.0+

安装

CocoaPods

podfile文件:

source 'https://github.com/CocoaPods/Specs.git'platform :ios, '10.0'use_frameworks!target '<Your Target Name>' do    pod 'Alamofire', '~> 4.4'end

然后到终端进入项目目录:

$ pod install

其他安装方法见gitHub


应用

首先导入Alamofire模块,发一个简单的GET请求


import AlamofireAlamofire.request("https://httpbin.org/get")

返回的回调:

Alamofire.request("https://httpbin.org/get").responseJSON { response in    print("Request: \(String(describing: response.request))")   // original url request    print("Response: \(String(describing: response.response))") // http url response    print("Result: \(response.result)")                         // response serialization result    if let json = response.result.value {        print("JSON: \(json)") // serialized json response    }    if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {        print("Data: \(utf8Text)") // original server data as UTF8 string    }}

Alamofire 包括默认回调总共有五种返回类型回调包括:


// Response Handler - Unserialized Responsefunc response(    queue: DispatchQueue?,    completionHandler: @escaping (DefaultDataResponse) -> Void)    -> Self// Response Data Handler - Serialized into Datafunc responseData(    queue: DispatchQueue?,    completionHandler: @escaping (DataResponse<Data>) -> Void)    -> Self// Response String Handler - Serialized into Stringfunc responseString(    queue: DispatchQueue?,    encoding: String.Encoding?,    completionHandler: @escaping (DataResponse<String>) -> Void)    -> Self// Response JSON Handler - Serialized into Anyfunc responseJSON(    queue: DispatchQueue?,    completionHandler: @escaping (DataResponse<Any>) -> Void)    -> Self// Response PropertyList (plist) Handler - Serialized into Anyfunc responsePropertyList(    queue: DispatchQueue?,    completionHandler: @escaping (DataResponse<Any>) -> Void))    -> Self

响应验证

在默认情况下,Alamofire对待任何完整的请求不管什么响应内容都是成功的,加上验证之后,在得到响应回调之前,先要经过验证,类型或者状态不匹配的则会报错。

手动验证

Alamofire.request("https://httpbin.org/get")    .validate(statusCode: 200..<300)    .validate(contentType: ["application/json"])    .responseData { response in        switch response.result {        case .success:            print("Validation Successful")        case .failure(let error):            print(error)        }    }


自动验证

自动验证状态码在200-300之间的区间,且内容类型是响应能接受的匹配类型。

Alamofire.request("https://httpbin.org/get").validate().responseJSON { response in    switch response.result {    case .success:        print("Validation Successful")    case .failure(let error):        print(error)    }}


响应缓存


响应缓存依赖于系统框架URLCache.


HTTP 请求方式


HTTP请求方式的枚举列表在下面的文件定义 RFC 7231 §4.3:

public enum HTTPMethod: String {    case options = "OPTIONS"    case get     = "GET"    case head    = "HEAD"    case post    = "POST"    case put     = "PUT"    case patch   = "PATCH"    case delete  = "DELETE"    case trace   = "TRACE"    case connect = "CONNECT"}

上面的那些方式的值可以当做Alamofire.request的method的参数设置

Alamofire.request("https://httpbin.org/get") // method defaults to `.get`Alamofire.request("https://httpbin.org/post", method: .post)Alamofire.request("https://httpbin.org/put", method: .put)Alamofire.request("https://httpbin.org/delete", method: .delete)

默认是Get方式


参数编码


Alamofire支持三种类型的参数编码包括:URL、JSON和PropertyList。它还可以支持任何自定义编码符合ParameterEncoding协议。

URL Encoding

GET请求的URL编码
let parameters: Parameters = ["foo": "bar"]// All three of these calls are equivalentAlamofire.request("https://httpbin.org/get", parameters: parameters) // encoding defaults to `URLEncoding.default`Alamofire.request("https://httpbin.org/get", parameters: parameters, encoding: URLEncoding.default)Alamofire.request("https://httpbin.org/get", parameters: parameters, encoding: URLEncoding(destination: .methodDependent))// https://httpbin.org/get?foo=bar

POST请求的URL编码
let parameters: Parameters = [    "foo": "bar",    "baz": ["a", 1],    "qux": [        "x": 1,        "y": 2,        "z": 3    ]]// All three of these calls are equivalentAlamofire.request("https://httpbin.org/post", method: .post, parameters: parameters)Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: URLEncoding.default)Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)// HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3

JSON Encoding

let parameters: Parameters = [    "foo": [1,2,3],    "bar": [        "baz": "qux"    ]]// Both calls are equivalentAlamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: JSONEncoding.default)Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: JSONEncoding(options: []))// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}

Property List Encoding

PropertyListEncoding使用PropertyListSerialization创建一个参数对象的plist表示,根据相关的格式和写作选项值,设置为请求的主体。content - type HTTP请求头字段的编码设置为application/x-plist.

Custom Encoding

struct JSONStringArrayEncoding: ParameterEncoding {private let array: [String]    init(array: [String]) {        self.array = array    }    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {        var urlRequest = try urlRequest.asURLRequest()        let data = try JSONSerialization.data(withJSONObject: array, options: [])        if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {            urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")        }        urlRequest.httpBody = data        return urlRequest    }}

给URLRequest 的参数手动编码

let url = URL(string: "https://httpbin.org/get")!var urlRequest = URLRequest(url: url)let parameters: Parameters = ["foo": "bar"]let encodedURLRequest = try URLEncoding.queryString.encode(urlRequest, with: parameters)



HTTP Headers(请求头)

给一个请求添加一个自定义的请求头,这个请求头必须是全局的,在你请求的时候更容易去获取和改变请求头。

let headers: HTTPHeaders = [    "Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",    "Accept": "application/json"]Alamofire.request("https://httpbin.org/headers", headers: headers).responseJSON { response in    debugPrint(response)}


身份认证

Authentication依赖于 URLCredential 和URLAuthenticationChallenge.这两个系统框架。

Supported Authentication Schemes

  • HTTP Basic
  • HTTP Digest
  • Kerberos
  • NTLM

HTTP Basic Authentication


let user = "user"let password = "password"Alamofire.request("https://httpbin.org/basic-auth/\(user)/\(password)")    .authenticate(user: user, password: password)    .responseJSON { response in        debugPrint(response)    }


根据服务器的实现方法,也可能需要一个授权头

let user = "user"let password = "password"var headers: HTTPHeaders = [:]if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {    headers[authorizationHeader.key] = authorizationHeader.value}Alamofire.request("https://httpbin.org/basic-auth/user/password", headers: headers)    .responseJSON { response in        debugPrint(response)    }

证书认证

let user = "user"let password = "password"let credential = URLCredential(user: user, password: password, persistence: .forSession)Alamofire.request("https://httpbin.org/basic-auth/\(user)/\(password)")    .authenticate(usingCredential: credential)    .responseJSON { response in        debugPrint(response)    }

下载文件


Alamofire.download("https://httpbin.org/image/png").responseData { response in    if let data = response.result.value {        let image = UIImage(data: data)    }}


下载文件目的地

let destination: DownloadRequest.DownloadFileDestination = { _, _ in    let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]    let fileURL = documentsURL.appendingPathComponent("pig.png")    return (fileURL, [.removePreviousFile, .createIntermediateDirectories])}Alamofire.download(urlString, to: destination).response { response in    print(response)    if response.error == nil, let imagePath = response.destinationURL?.path {        let image = UIImage(contentsOfFile: imagePath)    }}

你也可以使用建议目的地的API.

let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)Alamofire.download("https://httpbin.org/image/png", to: destination)


下载进度


Alamofire.download("https://httpbin.org/image/png")    .downloadProgress { progress in        print("Download Progress: \(progress.fractionCompleted)")    }    .responseData { response in        if let data = response.result.value {            let image = UIImage(data: data)        }    }


下载进度的API还可以设置线程参数,线程参数可以决定下载进度在哪个线程调起。

let utilityQueue = DispatchQueue.global(qos: .utility)Alamofire.download("https://httpbin.org/image/png")    .downloadProgress(queue: utilityQueue) { progress in        print("Download Progress: \(progress.fractionCompleted)")    }    .responseData { response in        if let data = response.result.value {            let image = UIImage(data: data)        }    }


恢复下载


class ImageRequestor {    private var resumeData: Data?    private var image: UIImage?    func fetchImage(completion: (UIImage?) -> Void) {        guard image == nil else { completion(image) ; return }        let destination: DownloadRequest.DownloadFileDestination = { _, _ in            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]            let fileURL = documentsURL.appendingPathComponent("pig.png")            return (fileURL, [.removePreviousFile, .createIntermediateDirectories])        }        let request: DownloadRequest        if let resumeData = resumeData {            request = Alamofire.download(resumingWith: resumeData)        } else {            request = Alamofire.download("https://httpbin.org/image/png")        }        request.responseData { response in            switch response.result {            case .success(let data):                self.image = UIImage(data: data)            case .failure:                self.resumeData = response.resumeData            }        }    }}

上传数据到服务器

上传Data类型:


let imageData = UIPNGRepresentation(image)!Alamofire.upload(imageData, to: "https://httpbin.org/post").responseJSON { response in    debugPrint(response)}


上传一个文件:


let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")Alamofire.upload(fileURL, to: "https://httpbin.org/post").responseJSON { response in    debugPrint(response)}


上传Multipart Form Data

Alamofire.upload(    multipartFormData: { multipartFormData in        multipartFormData.append(unicornImageURL, withName: "unicorn")        multipartFormData.append(rainbowImageURL, withName: "rainbow")    },    to: "https://httpbin.org/post",    encodingCompletion: { encodingResult in    switch encodingResult {    case .success(let upload, _, _):            upload.responseJSON { response in                debugPrint(response)            }    case .failure(let encodingError):        print(encodingError)    }    })

上传进度


let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")Alamofire.upload(fileURL, to: "https://httpbin.org/post")    .uploadProgress { progress in // main queue by default        print("Upload Progress: \(progress.fractionCompleted)")    }    .downloadProgress { progress in // main queue by default        print("Download Progress: \(progress.fractionCompleted)")    }    .responseJSON { response in        debugPrint(response)    }