一、NSURLSession
NSURLSession的主要功能是发起网络请求获取网络数据,是Apple的网络请求原生库之一。Alamofire就是对NSURLSession的封装,如果对NSURLSession不熟悉的话,那么Alamofire源码看起来会比较费劲的。因此我们先简单学习下NSURLSession。
从NSURLSession这个名字中我们不难看出,主要是URL + Session。顾名思义,NSURLSession是用来URL会话的。iOS的NSURLSession的主要功能是通过URL与服务器交流的。
一句话总结:我们的iOS客户端可以使用NSURLSession这个东西通过相应的URL与我们的服务器建立会话,然后通过此会话来完成一些交互任务(NSURLSessionTask)。Session有着不同的类型,每种类型的Session又可以执行不同类型的任务(Task)。接下来就来介绍一下Session的类型以及所执行的任务等。
1.NSURLSession的类型
在使用NSURLSession时你得知道你使用的是哪种类型的Session。从官方的NSURLSession API中不难看出,共有三种类型的Session:Default sessions,Ephemeral sessions,Background sessions。这三种Session我们可以通过NSURLSessionConfiguration来指定。
- 默认会话(Default Sessions)使用了持久的磁盘缓存,并且将证书存入用户的钥匙串中。它的特点是使用系统的缓存和凭证存储机制,适合处理需要缓存数据或保持会话状态的网络请求。
- 临时会话(Ephemeral Session)没有像磁盘中存入任何数据,与该会话相关的证书、缓存等都会存在RAM中。因此当你的App临时会话无效时,证书以及缓存等数据就会被清除掉。因此,它非常适合那些对隐私要求较高的场景。
- 后台会话(Background sessions)除了使用一个单独的线程来处理会话之外,与默认会话类似。适合处理需要长时间执行的任务,如文件下载和上传。此类会话通常会在后台传输文件,即使应用程序被挂起或终止,网络任务仍能继续执行,且完成后会通知应用。
Session在初始化时可以指定下方的任意一种SessionConfiguration:
let defaultSession = URLSession(configuration: .default)
let ephemeralSession = URLSession(configuration: .ephemeral)
let backgroundSession = URLSession(configuration: .background(withIdentifier: ".background"))
2. NSURLSession的各种任务
在一个Session会话中可以发起的任务可分为三种:数据任务(Data Task)、下载任务(Download Task)、上传任务(Upload Task)。在iOS8和OS X 10.10之前的版本中后台会话是不支持Data Task。下面来简述一下这三种任务。
- Data Task(数据任务)负责使用NSData对象来发送和接收数据。Data Task是为了那些简短的并且经常从服务器请求的数据而准备的。该任务可以每请求一次就对返回的数据进行一次处理。
- Download task(下载任务)以表单的形式接收一个文件的数据,该任务支持后台下载。
- Upload task(上传任务)以表单的形式上传一个文件的数据,该任务同样支持后台下载。
3、URL
(1)URL编码概述
无论是GET、POST还是其他的请求,与服务器交互的URL是需要进行编码的。因为进行URL编码的参数服务器那边才能进行解析,为了能和服务器正常的交互,我们需要对我们的参数进行转义和编码。URL就是互联网上资源的地址,用户和服务器都可以通过URL来找到其想访问的资源。RFC3986文档规定,URL中只允许包含英文字母(a-zA-Z)、数字(0-9)、“-_.~”4个特殊字符以及所有保留字符,如果你的URL中含有汉字,那么就需要对其进行转码了。RFC3986中指定了以下字符为保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]。
(2)URL编码的规则
在URL编码时有一定的规则,如下图是我们今天主要使用的URL格式的一个规则的一个图解:

需要注意的是图中Query的部分。其中,Path和Query之间使用的是?号进行分隔的,问号后边就是我们要传给服务器的参数了,该参数就是下方的Query的部分。在GET请求中Query是存放在URL后边,而在POST中是放在Request的Body中。
如果你的参数只是一个key-Value, 那么Query的形式就是key = value。如果你的参数是一个数组比如key = [itme1, item2, item3,……],那么你的Query的格式就是key[]=item1&key[itme2]&key[item3]……。如果你的参数是一个字典比如key = ["subKey1":"item1", "subKey2":"item2"], 那么Query对应的形式就是key[subKey1]=item1&key[subKey2]=item2.
接下来我们要做的就是将字典进行URL编码。
(3)将Dictionary进行URL编码
在iOS开发中,有时候我们从VC层或者VM层获取到的数据是一个字典,字典中存储的就是要发给服务器的数据参数。直接将字典转成二进制数据发送给服务器,服务器那边是没法解析iOS这边的字典的,得有一个统一的交互标准,这个标准就是URL编码。我们要做的就是讲字典进行URL编码,然后将编码后的东西在传给服务器,这样一来服务器那边就能解析到我们请求的参数了。下方折叠的这段代码就是从AlamoFire框架中摘抄出来的几个方法,位于ParameterEncoding.swift文件中。该段代码就是负责将字典类型的参数进行URL编码的,在编码过程中进行转义是少不了的。
import Foundation
//MARK: Alamofire中的三个方法该方法将字典转换成URL编码的字符
/*
用于将键值对转换为 URL 查询参数的形式。它递归地处理嵌套的字典和数组,
并根据键和值生成合适的查询组件(键值对)。
这些查询组件通常用于将复杂的字典或数组编码成 HTTP 请求 URL 中的查询字符串参数。
*/
private func query(_ parameters: [String: Any]) -> String {
var components: [(String, String)] = []
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
components += queryComponents(fromKey: key, value: value)
}
return components.map { "\($0)=\($1)" }.joined(separator: "&")
}
public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
var components: [(String, String)] = []
//如果 value 是一个字典类型 [String: Any],这里会将字典的键用方括号括起来进行拼接,比如如果传入的 key 是 "user",而 nestedKey 是 "name",那么组合后的键会变为 "user[name]",从而表示字典的嵌套结构。
if let dictionary = value as? [String: Any] {
for (nestedKey, value) in dictionary {
components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
}
} //如果 value 是数组类型 [Any],代码会遍历数组中的每个值。
else if let array = value as? [Any] {
for value in array {
components += queryComponents(fromKey: arrayEncoding.encode(key: key

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



