iOS--NSURLSession && Alamofire流程源码解析(万字详解版)

一、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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值