Alamofire框架的使用一 —— 基本用法

对于使用Objective-C的开发者,一定非常熟悉AFNetworking这个网络框架。在苹果推出的Swift之后,AFNetworking的作者专门用Swift来编写一个类似AFNetworking的网络框架,称为AlamofireAlamofire地址 >>

我分两篇文章介绍如何使用Alamofire框架。文章的内容主要是翻译Alamofire的readme。第二篇文章 >>

功能

  • 链式请求/响应方法
  • URL / JSON / plist参数编码
  • 上传文件/数据/流/多表单数据
  • 使用请求或者断点下载来下载文件
  • 使用URL凭据进行身份认证
  • HTTP响应验证
  • 包含进度的上传和下载闭包
  • cURL命令的输出
  • 动态适配和重试请求
  • TLS证书和Public Key Pinning
  • 网络可达性
  • 全面的单元和集成测试覆盖率

组件库

为了让Alamofire专注于核心网络的实现,Alamofire生态系统还有另外两个库:

  • AlamofireImage:一个图片库,包括图像响应序列化器、UIImageUIImageView的扩展、自定义图像滤镜、内存中自动清除和基于优先级的图像下载系统。
  • AlamofireNetworkActivityIndicator:控制iOS应用的网络活动指示器。包含可配置的延迟计时器来帮助减少闪光,并且支持不受Alamofire管理的URLSession实例。

要求的使用环境

  • iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 8.3+
  • Swift 3.1+

安装方法

CocoaPods

  1. source 'https://github.com/CocoaPods/Specs.git'
  2. platform :ios, '10.0'
  3. use_frameworks!
  4. target '项目名称' do
  5. pod 'Alamofire', '~> 4.7'
  6. end

iOS版本和Alamofire版本可以自己根据实际情况自行更改。CocoaPods是比较常用的第三方库管理工具,其他方法就不详细说了。

如何使用

发请求

  1. Alamofire.request("http://baidu.com/")

响应处理

直接在请求后面用点语法链接响应处理:

  1. Alamofire.request("https://httpbin.org/get").responseJSON { response in
  2. print(response.request) // 原始的URL请求
  3. print(response.response) // HTTP URL响应
  4. print(response.data) // 服务器返回的数据
  5. print(response.result) // 响应序列化结果,在这个闭包里,存储的是JSON数据
  6. if let JSON = response.result.value {
  7. print("JSON: \(JSON)")
  8. }
  9. }

在上面的例子中,responseJSON handler直接拼接到请求后面,当请求完成后被调用。这个闭包一旦收到响应后,就会处理这个响应,并不会因为等待服务器的响应而造成阻塞执行。请求的结果仅在响应闭包的范围内可用。其他任何与服务器返回的响应或者数据相关的操作,都必须在这个闭包内执行。

Alamofire默认情况下包含五种不同的响应handler:

  1. // 响应 Handler - 未序列化的响应
  2. func response(
  3. queue: DispatchQueue?,
  4. completionHandler: @escaping (DefaultDataResponse) -> Void)
  5. -> Self
  6. // 响应数据 Handler - 序列化成数据类型
  7. func responseData(
  8. queue: DispatchQueue?,
  9. completionHandler: @escaping (DataResponse<Data>) -> Void)
  10. -> Self
  11. // 响应字符串 Handler - 序列化成字符串类型
  12. func responseString(
  13. queue: DispatchQueue?,
  14. encoding: String.Encoding?,
  15. completionHandler: @escaping (DataResponse<String>) -> Void)
  16. -> Self
  17. // 响应 JSON Handler - 序列化成Any类型
  18. func responseJSON(
  19. queue: DispatchQueue?,
  20. completionHandler: @escaping (DataResponse<Any>) -> Void)
  21. -> Self
  22. // 响应 PropertyList (plist) Handler - 序列化成Any类型
  23. func responsePropertyList(
  24. queue: DispatchQueue?,
  25. completionHandler: @escaping (DataResponse<Any>) -> Void))
  26. -> Self

所有的响应handler都不会对响应进行验证。也就是说响应状态码在400..<500500..<600范围内,都不会触发错误。

响应 Handler

response handler不处理任何响应数据。它仅仅是从URL session delegate中转发信息。

  1. Alamofire.request("https://httpbin.org/get").response { response in
  2. print("Request: \(response.request)")
  3. print("Response: \(response.response)")
  4. print("Error: \(response.error)")
  5. if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
  6. print("Data: \(utf8Text)")
  7. }
  8. }

一般情况下不建议使用这种没有响应序列化器的handler,而应该使用下面有特定序列化器的handler。

响应数据 Handler

responseData handler使用responseDataSerializer(这个对象把服务器的数据序列化成其他类型)来提取服务器返回的数据。如果没有返回错误并且有数据返回,那么响应Result将会是.successvalueData类型。

  1. Alamofire.request("https://httpbin.org/get").responseData { response in
  2. debugPrint("All Response Info: \(response)")
  3. if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
  4. print("Data: \(utf8Text)")
  5. }
  6. }
响应字符串 Handler

responseString handler使用responseStringSerializer对象根据指定的编码格式把服务器返回的数据转换成String。如果没有返回错误并且服务器的数据成功地转换为String,那么响应Result将会是.successvalueString类型。

  1. Alamofire.request("https://httpbin.org/get").responseString { response in
  2. print("Success: \(response.result.isSuccess)")
  3. print("Response String: \(response.result.value)")
  4. }

如果没有指定编码格式,将会使用服务器的HTTPURLResponse指定的格式。如果服务器无法确定编码格式,那么默认使用.isoLatin1

响应 JSON Handler

responseJSON handler使用responseJSONSerializer根据指定的JSONSerialization.ReadingOptions把服务器返回的数据转换成Any类型。如果没有返回错误并且服务器的数据成功地转换为JSON对象,那么响应Result将会是.successvalueAny类型。

  1. Alamofire.request("https://httpbin.org/get").responseJSON { response in
  2. debugPrint(response)
  3. if let json = response.result.value {
  4. print("JSON: \(json)")
  5. }
  6. }

所有JSON的序列化,都是使用JSONSerialization完成的。

链式响应handler

响应handler可以链接在一起:

  1. Alamofire.request("https://httpbin.org/get")
  2. .responseString { response in
  3. print("Response String: \(response.result.value)")
  4. }
  5. .responseJSON { response in
  6. print("Response JSON: \(response.result.value)")
  7. }

注意:在同一个请求中使用多个响应handler,要求服务器的数据会被序列化多次,每次对应一个handler。

响应handler队列

默认情况下,响应handler是在主队列执行的。但是我们也可以自定义队列:

  1. let utilityQueue = DispatchQueue.global(qos: .utility)
  2. Alamofire.request("https://httpbin.org/get").responseJSON(queue: utilityQueue) { response in
  3. print("Executing response handler on utility queue")
  4. }

响应验证

默认情况下,Alamofire把所有完成的请求当做是成功的请求,无论响应的内容是什么。如果响应有一个不能被接受的状态码或者MIME类型,在响应handler之前调用validate将会产生错误。

手动验证
  1. Alamofire.request("https://httpbin.org/get")
  2. .validate(statusCode: 200..<300)
  3. .validate(contentType: ["application/json"])
  4. .responseData { response in
  5. switch response.result {
  6. case .success:
  7. print("Validation Successful")
  8. case .failure(let error):
  9. print(error)
  10. }
  11. }
自动验证

自动验证在200…299范围内的状态码;如果请求头中有指定Accept,那么也会验证响应头的与请求头Accept一样的Content-Type

  1. Alamofire.request("https://httpbin.org/get").validate().responseJSON { response in
  2. switch response.result {
  3. case .success:
  4. print("Validation Successful")
  5. case .failure(let error):
  6. print(error)
  7. }
  8. }

响应缓存

响应缓存是使用系统的框架URLCache来处理的。它提供了内存和磁盘上的缓存,并允许我们控制内存和磁盘的大小。

默认情况下,Alamofire利用共享的URLCache

HTTP方法

HTTPMethod列举了下面的这些方法:

  1. public enum HTTPMethod: String {
  2. case options = "OPTIONS"
  3. case get = "GET"
  4. case head = "HEAD"
  5. case post = "POST"
  6. case put = "PUT"
  7. case patch = "PATCH"
  8. case delete = "DELETE"
  9. case trace = "TRACE"
  10. case connect = "CONNECT"
  11. }

在使用Alamofire.request时,可以传入方法参数:

  1. Alamofire.request("https://httpbin.org/get") // 默认是get请求
  2. Alamofire.request("https://httpbin.org/post", method: .post)
  3. Alamofire.request("https://httpbin.org/put", method: .put)
  4. Alamofire.request("https://httpbin.org/delete", method: .delete)

参数编码

Alamofire支持三种参数编码:URLJSONPropertyList。还支持遵循了ParameterEncoding协议的自定义编码。

URL编码

URLEncoding类型创建了一个URL编码的查询字符串来设置或者添加到一个现有的URL查询字符串,或者设置URL请求的请求体。查询字符串是否被设置或者添加到现有的URL查询字符串,或者被作为HTTP请求体,决定于编码的Destination。编码的Destination有三个case:

  • .methodDependent:为GETHEADDELETE请求使用编码查询字符串来设置或者添加到现有查询字符串,并且使用其他HTTP方法来设置请求体。
  • .queryString:设置或者添加编码查询字符串到现有查询字符串
  • .httpBody:把编码查询字符串作为URL请求的请求体

一个编码请求的请求体的Content-Type字段被设置为application/x-www-form-urlencoded; charset=utf-8。因为没有公开的标准说明如何编码集合类型,所以按照惯例在key后面添加[]来表示数组的值(foo[]=1&foo[]=2),在key外面包一个中括号来表示字典的值(foo[bar]=baz)。

使用URL编码参数的GET请求
  1. let parameters: Parameters = ["foo": "bar"]
  2. // 下面这三种写法是等价的
  3. Alamofire.request("https://httpbin.org/get", parameters: parameters) // encoding 默认是`URLEncoding.default`
  4. Alamofire.request("https://httpbin.org/get", parameters: parameters, encoding: URLEncoding.default)
  5. Alamofire.request("https://httpbin.org/get", parameters: parameters, encoding: URLEncoding(destination: .methodDependent))
  6. // https://httpbin.org/get?foo=bar
使用URL编码参数的POST请求
  1. let parameters: Parameters = [
  2. "foo": "bar",
  3. "baz": ["a", 1],
  4. "qux": [
  5. "x": 1,
  6. "y": 2,
  7. "z": 3
  8. ]
  9. ]
  10. // 下面这三种写法是等价的
  11. Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters)
  12. Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: URLEncoding.default)
  13. Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)
  14. // HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
设置Bool类型参数的编码

URLEncoding.BoolEncoding提供了两种编码方式:

  • .numeric:把true编码为1false编码为0
  • .literal:把true编码为truefalse编码为false

默认情况下:Alamofire使用.numeric

可以使用下面的初始化函数来创建URLEncoding,指定Bool编码的类型:

  1. let encoding = URLEncoding(boolEncoding: .literal)
设置Array类型参数编码

URLEncoding.ArrayEncoding提供了两种编码方式:

  • .brackets: 在每个元素值的key后面加上一个[],如foo=[1,2]编码成foo[]=1&foo[]=2
  • .noBrackets:不添加[],例如foo=[1,2]编码成``foo=1&foo=2`

默认情况下,Alamofire使用.brackets

可以使用下面的初始化函数来创建URLEncoding,指定Array编码的类型:

  1. let encoding = URLEncoding(arrayEncoding: .noBrackets)
JSON编码

JSONEncoding类型创建了一个JOSN对象,并作为请求体。编码请求的请求头的Content-Type请求字段被设置为application/json

使用JSON编码参数的POST请求
  1. let parameters: Parameters = [
  2. "foo": [1,2,3],
  3. "bar": [
  4. "baz": "qux"
  5. ]
  6. ]
  7. // 下面这两种写法是等价的
  8. Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: JSONEncoding.default)
  9. Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters, encoding: JSONEncoding(options: []))
  10. // HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
属性列表编码

PropertyListEncoding根据关联格式和写选项值,使用PropertyListSerialization来创建一个属性列表对象,并作为请求体。编码请求的请求头的Content-Type请求字段被设置为application/x-plist

自定义编码

如果提供的ParameterEncoding类型不能满足我们的要求,可以创建自定义编码。下面演示如何快速自定义一个JSONStringArrayEncoding类型把JSON字符串数组编码到请求中。

  1. struct JSONStringArrayEncoding: ParameterEncoding {
  2. private let array: [String]
  3. init(array: [String]) {
  4. self.array = array
  5. }
  6. func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
  7. var urlRequest = urlRequest.urlRequest
  8. let data = try JSONSerialization.data(withJSONObject: array, options: [])
  9. if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
  10. urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
  11. }
  12. urlRequest.httpBody = data
  13. return urlRequest
  14. }
  15. }
手动URL请求参数编码

ParameterEncodingAPI可以在创建网络请求外面使用。

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

HTTP请求头

可以直接在请求方法添加自定义HTTP请求头,这有利于我们在请求中添加请求头。

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

对于那些不变的请求头,建议在URLSessionConfiguration设置,这样就可以自动被用于任何URLSession创建的URLSessionTask

默认的Alamofire SessionManager为每一个请求提供了一个默认的请求头集合,包括:

  • Accept-Encoding,默认是gzip;q=1.0, compress;q=0.5
  • Accept-Language,默认是系统的前6个偏好语言,格式类似于en;q=1.0
  • User-Agent,包含当前应用程序的版本信息。例如iOS Example/1.0 (com.alamofire.iOS-Example; build:1; iOS 10.0.0) Alamofire/4.0.0

如果要自定义这些请求头集合,我们必须创建一个自定义的URLSessionConfigurationdefaultHTTPHeaders属性将会被更新,并且自定义的会话配置也会应用到新的SessionManager实例。

认证

认证是使用系统框架URLCredentialURLAuthenticationChallenge实现的。

支持的认证方案
  • HTTP Basic
  • HTTP Digest
  • Kerberos
  • NTLM
HTTP Basic认证

在合适的时候,在一个请求的authenticate方法会自动提供一个URLCredentialURLAuthenticationChallenge

  1. let user = "user"
  2. let password = "password"
  3. Alamofire.request("https://httpbin.org/basic-auth/\(user)/\(password)")
  4. .authenticate(user: user, password: password)
  5. .responseJSON { response in
  6. debugPrint(response)
  7. }

根据服务器实现,Authorization header也可能是适合的:

  1. let user = "user"
  2. let password = "password"
  3. var headers: HTTPHeaders = [:]
  4. if let authorizationHeader = Request.authorizationHeader(user: user, password: password) {
  5. headers[authorizationHeader.key] = authorizationHeader.value
  6. }
  7. Alamofire.request("https://httpbin.org/basic-auth/user/password", headers: headers)
  8. .responseJSON { response in
  9. debugPrint(response)
  10. }
使用URLCredential认证
  1. let user = "user"
  2. let password = "password"
  3. let credential = URLCredential(user: user, password: password, persistence: .forSession)
  4. Alamofire.request("https://httpbin.org/basic-auth/\(user)/\(password)")
  5. .authenticate(usingCredential: credential)
  6. .responseJSON { response in
  7. debugPrint(response)
  8. }

注意:使用URLCredential来做认证,如果服务器发出一个challenge,底层的URLSession实际上最终会发两次请求。第一次请求不会包含credential,并且可能会触发服务器发出一个challenge。这个challenge会被Alamofire接收,credential会被添加,然后URLSessin会重试请求。

将数据下载到文件

Alamofire可以把服务器的数据下载到内存(in-memory)或者硬盘(on-disk)中。所有Alamofire.requestAPI下载的数据都是存储在内存中。这比较适合小文件,更高效;但是不适合大文件,因为大文件会把内存耗尽。我们要使用Alamofire.downloadAPI把服务器的数据下载到硬盘中。

下面这个方法只适用于macOS。因为在其他平台不允许在应用沙盒外访问文件系统。下面会讲到如何在其他平台下载文件。

  1. Alamofire.download("https://httpbin.org/image/png").responseData { response in
  2. if let data = response.result.value {
  3. let image = UIImage(data: data)
  4. }
  5. }
下载文件存储位置

我们可以提供一个DownloadFileDestination闭包把临时文件夹的文件移动到一个目标文件夹。在临时文件真正移动到destinationURL之前,闭包内部指定的DownloadOptions将会被执行。目前支持的DownloadOptions有下面两个:

  • .createIntermediateDirectories:如果指定了目标URL,将会创建中间目录。
  • .removePreviousFile:如果指定了目标URL,将会移除之前的文件
  1. let destination: DownloadRequest.DownloadFileDestination = { _, _ in
  2. let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
  3. let fileURL = documentsURL.appendPathComponent("pig.png")
  4. return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
  5. }
  6. Alamofire.download(urlString, to: destination).response { response in
  7. print(response)
  8. if response.error == nil, let imagePath = response.destinationURL?.path {
  9. let image = UIImage(contentsOfFile: imagePath)
  10. }
  11. }

也可以直接使用建议的下载目标API:

  1. let destination = DownloadRequest.suggestedDownloadDestination(directory: .documentDirectory)
  2. Alamofire.download("https://httpbin.org/image/png", to: destination)
下载进度

所有的DownloadRequest都可以使用downloadProgressAPI来反馈下载进度。

  1. Alamofire.download("https://httpbin.org/image/png")
  2. .downloadProgress { progress in
  3. print("Download Progress: \(progress.fractionCompleted)")
  4. }
  5. .responseData { response in
  6. if let data = response.result.value {
  7. let image = UIImage(data: data)
  8. }
  9. }

downloadProgressAPI还可以接受一个queue参数来指定下载进度闭包在哪个DispatchQueue中执行。

  1. let utilityQueue = DispatchQueue.global(qos: .utility)
  2. Alamofire.download("https://httpbin.org/image/png")
  3. .downloadProgress(queue: utilityQueue) { progress in
  4. print("Download Progress: \(progress.fractionCompleted)")
  5. }
  6. .responseData { response in
  7. if let data = response.result.value {
  8. let image = UIImage(data: data)
  9. }
  10. }
恢复下载

如果一个DownloadRequest被取消或中断,底层的URL会话会生成一个恢复数据。恢复数据可以被重新利用并在中断的位置继续下载。恢复数据可以通过下载响应访问,然后在重新开始请求的时候被利用。

重要:在iOS 10 - 10.2, macOS 10.12 - 10.12.2, tvOS 10 - 10.1, watchOS 3 - 3.1.1中,resumeData会被后台URL会话配置破坏。因为在resumeData的生成逻辑有一个底层的bug,不能恢复下载。具体情况可以到Stack Overflow看看。

  1. class ImageRequestor {
  2. private var resumeData: Data?
  3. private var image: UIImage?
  4. func fetchImage(completion: (UIImage?) -> Void) {
  5. guard image == nil else { completion(image) ; return }
  6. let destination: DownloadRequest.DownloadFileDestination = { _, _ in
  7. let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
  8. let fileURL = documentsURL.appendPathComponent("pig.png")
  9. return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
  10. }
  11. let request: DownloadRequest
  12. if let resumeData = resumeData {
  13. request = Alamofire.download(resumingWith: resumeData)
  14. } else {
  15. request = Alamofire.download("https://httpbin.org/image/png")
  16. }
  17. request.responseData { response in
  18. switch response.result {
  19. case .success(let data):
  20. self.image = UIImage(data: data)
  21. case .failure:
  22. self.resumeData = response.resumeData
  23. }
  24. }
  25. }
  26. }

上传数据到服务器

使用JOSN或者URL编码参数上传一些小数据到服务器,使用Alamofire.request API就已经足够了。如果需要发送很大的数据,需要使用Alamofire.upload API。当我们需要在后台上传数据时,也可以使用Alamofire.upload

上传数据
  1. let imageData = UIPNGRepresentation(image)!
  2. Alamofire.upload(imageData, to: "https://httpbin.org/post").responseJSON { response in
  3. debugPrint(response)
  4. }
上传文件
  1. let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
  2. Alamofire.upload(fileURL, to: "https://httpbin.org/post").responseJSON { response in
  3. debugPrint(response)
  4. }
上传多部分表单数据
  1. Alamofire.upload(
  2. multipartFormData: { multipartFormData in
  3. multipartFormData.append(unicornImageURL, withName: "unicorn")
  4. multipartFormData.append(rainbowImageURL, withName: "rainbow")
  5. },
  6. to: "https://httpbin.org/post",
  7. encodingCompletion: { encodingResult in
  8. switch encodingResult {
  9. case .success(let upload, _, _):
  10. upload.responseJSON { response in
  11. debugPrint(response)
  12. }
  13. case .failure(let encodingError):
  14. print(encodingError)
  15. }
  16. }
  17. )
上传进度

所有的UploadRequest都可以使用uploadProgressdownloadProgress APIs来反馈上传和下载进度。

  1. let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
  2. Alamofire.upload(fileURL, to: "https://httpbin.org/post")
  3. .uploadProgress { progress in // 默认在主线程中执行
  4. print("Upload Progress: \(progress.fractionCompleted)")
  5. }
  6. .downloadProgress { progress in // 默认在主线程中执行
  7. print("Download Progress: \(progress.fractionCompleted)")
  8. }
  9. .responseJSON { response in
  10. debugPrint(response)
  11. }

统计指标

时间表

Alamofire在一个请求周期内收集时间,并创建一个Tineline对象,它是响应类型的一个属性。

  1. Alamofire.request("https://httpbin.org/get").responseJSON { response in
  2. print(response.timeline)
  3. }

上面的Timeline信息包括:

  • Latency: 0.428 seconds (延迟)
  • Request Duration: 0.428 seconds (请求时间)
  • Serialization Duration: 0.001 seconds (序列化时间)
  • Total Duration: 0.429 seconds (总时间)
URL会话任务指标

在iOS和tvOS 10和macOS 10.12中,苹果发布了新的URLSessionTaskMetrics APIs。这个任务指标封装了关于请求和响应执行的神奇统计信息。这个API和Timeline非常相似,但是提供了很多Alamofire没有提供的统计信息。这些指标可以通过任何响应去访问。

  1. Alamofire.request("https://httpbin.org/get").responseJSON { response in
  2. print(response.metrics)
  3. }

注意:这些API只能在iOS和tvOS 10和macOS 10.12中使用。所以,根据部署目标,可能需要加入版本判断:

  1. Alamofire.request("https://httpbin.org/get").responseJSON { response in
  2. if #available(iOS 10.0. *) {
  3. print(response.metrics)
  4. }
  5. }

cURL命令输出

调试平台问题很让人厌烦。庆幸的是,Alamofire的Request对象遵循了CustomStringConvertibleCustomDebugStringConvertible协议来提供一些非常有用的调试工具。

CustomStringConvertible
  1. let request = Alamofire.request("https://httpbin.org/ip")
  2. print(request)
  3. // GET https://httpbin.org/ip (200)
CustomDebugStringConvertible
  1. let request = Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"])
  2. debugPrint(request)

输出:

  1. $ curl -i \
  2. -H "User-Agent: Alamofire/4.0.0" \
  3. -H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
  4. -H "Accept-Language: en;q=1.0,fr;q=0.9,de;q=0.8,zh-Hans;q=0.7,zh-Hant;q=0.6,ja;q=0.5" \
  5. "https://httpbin.org/get?foo=bar"

第一部分完。

作者:Lebron_James
链接:https://www.jianshu.com/p/f8c3adb056cf
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

【iOS开发】Alamofire框架的使用一基本用法的更多相关文章

  1. 李洪强iOS开发之 - enum与typedef enum的用法

    李洪强iOS开发之 - enum与typedef enum的用法 01 - 定义枚举类型 上面我们就在ViewController.h定义了一个枚举类型,枚举类型的值默认是连续的自然数,例如例子中的T ...

  2. iOS开发基础框架

    ---恢复内容开始--- //appdelegate ////  AppDelegate.m//  iOS开发架构////  Copyright © 2016年 Chason. All rights ...

  3. iOS开发多线程篇 08 —GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  4. 【iOS开发】Alamofire框架的使用二 高级用法

    Alamofire是在URLSession和URL加载系统的基础上写的.所以,为了更好地学习这个框架,建议先熟悉下列几个底层网络协议栈: URL Loading System Programming ...

  5. iOS开发-网络框架-b

    网络框架(以下称NJAFNetworking)是基于AFNetworking框架的简单封装,基本功能包括POST请求,GET请求,上传文件,下载文件,网络状态,缓存等. 为什么要使用NJAFNetwo ...

  6. iOS开发UIKit框架-可视化编程-XIB

    1. Interface Builder 可视化编程 1> 概述 GUI : 图形用户界面(Graphical User Interface, 简称GUI, 又称图形化界面) 是指采用图形方式显 ...

  7. 简单搭建iOS开发项目框架

    今天我们来谈谈如何搭建框架,框架需要做一些什么. 第一步:找到我们的目标我们的目标是让其他开发人员拿到手后即可写页面,不再需要考虑其他的问题. 第二步:我们需要做哪些东西各位跟着我一步一步来进行. 假 ...

  8. iOS开发-CoreMotion框架(加速计和陀螺仪)

    CoreMotion是一个专门处理Motion的框架,其中包含了两个部分加速度计和陀螺仪,在iOS4之前加速度计是由UIAccelerometer类来负责采集数据,现在一般都是用CoreMotion来 ...

  9. iOS开发-CoreMotion框架

    转自: CoreMotion是一个专门处理Motion的框架,其中包含了两个部分 加速度计和陀螺仪,在iOS4之前加速度计是由 UIAccelerometer 类 来负责采集数据,现在一般都是用Cor ...

随机推荐

  1. Java部署项目命令学习小结

    前言: 暂无 零:java -h 和很多linux命令一样,我们第一步先通过“java -h”命令查看java命令的使用语法,其输出如下 [root@wxapp203 basesoft]# java ...

  2. CKEditor上传视频(java)

    CKEditor上传视频 CKEditor批量上传图片flvplayer.swf播放器CKEditor整合包(v4.6.1) ------------------------------------ ...

  3. 我要曝光!CDN 省钱大法!

    七夕节刚过去,小明却特别郁闷,因为七夕当天,他错过了和远在北京的女神表白的机会.事情的经过是怎样的呢?为了在七夕当天送给自己女神一件礼物,小明在某购物网站上花重金购买了特别的礼物,礼物是从广东发送,结 ...

  4. TDX指标的理解与改造(价格到达指标线提醒)

    目的:画线指标理解,并同时改造成条件选股指标. 参考:https://mp.csdn.net/postedit/83176406 #ff7700 hex color  https://www.colo ...

  5. RabbitMQ学习笔记(三) 发布与订阅

    发布与订阅 在我们使用手机发送消息的时候,即可以选择给单个手机号码发送消息,也可以选择多个手机号码,群发消息. 前面学习工作队列的时候,我们使用的场景是一个消息只能被一个消费者程序实例接收并处理,但是 ...

  6. NFS的安装

    NFS的安装鸟哥地址:http://vbird.dic.ksu.edu.tw/linux_server/0330nfs_2.php 13.2 NFS Server 端的设定 既然要使用 NFS 的话, ...

  7. 通过 Ansible 安装 Docker

    本文的演示环境为 ubuntu 16.04. 先在 Ansible Galaxy 搜索 docker,由 geerlingguy 贡献的 docker role 是目前最受欢迎的: 通过 ansibl ...

  8. js转base64(数字)

    var name='测试文字'; var t_name=encodeURIComponent(name); t_name=window.btoa(t_name); console.log(t_name ...

  9. 表达式目录树(Expression)

    一:什么是表达式树 Expression我们称为是表达式树,是一种数据结构体,用于存储需要计算,运算的一种结构,这种结构可以只是存储,而不进行运算.通常表达式目录树是配合Lambda一起来使用的,la ...

  10. .Net中Log4Net的使用

    2018-08-23 .Net中Log4Net的使用 一.log4net 分类型记录日志存放多个日志文件 1.在webconfig里添加配置 1.1 在<configSections> 中 ...