序:做过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、完整的单元检测
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target '' do pod 'Alamofire', '~> 4.4' end
然后到终端进入项目目录:
$ pod install
其他安装方法见gitHub
import Alamofire Alamofire.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 Response func response( queue: DispatchQueue?, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self // Response Data Handler - Serialized into Data func responseData( queue: DispatchQueue?, completionHandler: @escaping (DataResponse) -> Void) -> Self // Response String Handler - Serialized into String func responseString( queue: DispatchQueue?, encoding: String.Encoding?, completionHandler: @escaping (DataResponse<String>) -> Void) -> Self // Response JSON Handler - Serialized into Any func responseJSON( queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Any>) -> Void) -> Self // Response PropertyList (plist) Handler - Serialized into Any func responsePropertyList( queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Any>) -> Void)) -> Self
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) } }
Alamofire.request("https://httpbin.org/get").validate().responseJSON { response in switch response.result { case .success: print("Validation Successful") case .failure(let error): print(error) } }
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("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)
let parameters: Parameters = ["foo": "bar"] // All three of these calls are equivalent Alamofire.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
let parameters: Parameters = [ "foo": "bar", "baz": ["a", 1], "qux": [ "x": 1, "y": 2, "z": 3 ] ] // All three of these calls are equivalent Alamofire.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
let parameters: Parameters = [ "foo": [1,2,3], "bar": [ "baz": "qux" ] ] // Both calls are equivalent Alamofire.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"}}
application/x-plist
.。
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 } }
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)
let headers: HTTPHeaders = [ "Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", "Accept": "application/json" ] Alamofire.request("https://httpbin.org/headers", headers: headers).responseJSON { response in debugPrint(response) }
URLCredential
和URLAuthenticationChallenge
.这两个系统框架。
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)
}
}
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) } }
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 } } } }
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) }
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) }