一、前言:为什么你用了多年 AFN,依然不懂底层?
几乎所有 iOS 开发者日常开发百分百依赖 AFNetworking,但绝大多数人只会调用GET/POST方法,对底层一无所知:
不知道 AFN 3.x 彻底废弃 NSURLConnection,全系基于NSURLSession
不清楚 AFN 为什么默认所有请求串行、队列最大并发数4
遇到请求超时、重复请求、证书报错、序列化失败只会瞎改参数
不懂 AFN 代理转发机制,疑惑「为什么 Session 代理是空的还能回调」
分不清 NSURLSession 三种 Task 差异,下载/上传断点续传原理模糊
AFNetworking 不是黑盒魔法,它只是对苹果原生NSURLSession的工程级封装:封装序列化、异常处理、证书校验、网络监听、线程调度、回调优化。
想要彻底解决网络疑难问题、搞定面试网络底层题,必须吃透NSURLSession 原生底层 + AFN 封装逻辑。
本文延续系列博客风格:原理拆解 + 完整流程 + 大量实战案例 + 源码核心逻辑 + 踩坑复盘 + 面试题,从零打通 iOS 网络底层。
二、iOS 网络 API 迭代:为什么 NSURLSession 取代一切?
1. 三代网络 API 迭代对比
网络API | 诞生时代 | 核心问题 | 现状 |
|---|---|---|---|
NSURLRequest + NSURLConnection | iOS2.0 | 无任务管理、无法断点续传、内存泄漏严重、串行阻塞、后台下载鸡肋 | iOS9 废弃,彻底淘汰 |
NSURLSession | iOS7.0 | 无明显短板,支持任务管理、断点续传、后台任务、并发控制、缓存优化 | 目前官方主推、AFN 底层核心 |
Network.framework | iOS13.0 | 基于TCP/UDP底层,更灵活,适合长连接、自定义协议 | 进阶场景使用,常规业务依然用 NSURLSession |
核心结论:AFNetworking 3.0+ 彻底抛弃 NSURLConnection,全系封装 NSURLSession,这也是 AFN 稳定、高性能的底层根源。
三、NSURLSession 原生底层核心架构(必懂)
NSURLSession 是苹果提供的高性能、异步、可管理网络会话层,所有网络请求都基于「会话 + 任务」模型。
1. 三大核心组件
(1)NSURLSession:网络会话管理者
全局会话载体,负责配置全局网络参数、管理所有网络任务、控制并发、缓存、Cookie、协议、超时等。
(2)NSURLSessionConfiguration:会话配置类
决定 Session 整体行为,三种配置模式:
defaultConfiguration:默认配置,有内存缓存+磁盘缓存,Cookie持久化(AFN 默认使用)
ephemeralConfiguration:临时会话,无磁盘缓存、无Cookie持久化,适合隐私请求
backgroundConfiguration:后台会话,支持 App 退后台继续下载/上传
(3)NSURLSessionTask:真正的网络任务
所有请求都是 Task,Session 只是管理者,Task 才是真正发起请求、接收数据的对象。
三种 Task 类型,覆盖所有业务场景:
NSURLSessionDataTask:普通 GET/POST 接口请求,内存接收数据,适用于短请求
NSURLSessionDownloadTask:文件下载,自动写入沙盒,支持断点续传、后台下载
NSURLSessionUploadTask:文件/数据流上传,支持大文件分片、后台上传
2. NSURLSession 原生完整请求流程
原生无封装情况下,一次网络请求完整步骤:
创建NSURLSessionConfiguration配置参数
基于配置初始化NSURLSession会话
创建NSURLRequest(请求头、请求方式、超时、参数)
创建对应 Task(DataTask/DownloadTask/UploadTask)
手动调用 resume 启动任务(重点:Task 默认暂停状态)
通过代理接收数据、进度、完成回调
任务结束,Session 回收资源
3. 原生 NSURLSession GET 实战案例(无任何第三方)
// 1. 创建配置 NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; config.timeoutIntervalForRequest = 15; // 请求超时15s config.HTTPMaximumConnectionsPerHost = 4; // 单域名最大并发4 // 2. 创建会话 NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; // 3. 创建请求 NSURL *url = [NSURL URLWithString:@"https://httpbin.org/get"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 4. 创建任务并启动 NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { NSLog(@"请求失败:%@",error.localizedDescription); } else { NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"原生请求结果:%@",dict); } }]; [task resume]; // 必须手动resume,任务才会执行核心痛点:原生写法繁琐、无自动序列化、无统一异常处理、无进度回调、无证书适配、难以批量管理任务,这就是 AFN 存在的意义。
四、AFNetworking 整体架构与五大核心模块
AFN 不是简单封装,是一套高内聚、低耦合的五层架构,每个模块职责单一,这也是 AFN 长期稳定的核心原因。
1. AFN 五大核心模块
网络通信模块(核心):
AFURLSessionManager、AFHTTPSessionManager,封装 NSURLSession 所有能力,管理任务、代理、并发序列化模块:
AFHTTPRequestSerializer/AFHTTPResponseSerializer,自动处理 JSON/表单/二进制参数与响应解析安全策略模块:
AFSecurityPolicy,封装 TLS 证书校验、SSL 双向认证、防中间人攻击网络状态模块:
AFNetworkReachabilityManager,实时监听 2G/3G/4G/WiFi/无网状态UIKit 扩展模块:图片异步加载、网络状态 HUD、进度条等业务扩展能力
2. 核心类继承关系(面试高频)
AFHTTPSessionManager → 继承 AFURLSessionManager → 封装 NSURLSession
很多人混淆两个 Manager:
AFURLSessionManager:底层基础类,通用网络会话,不局限 HTTP,可自定义协议
AFHTTPSessionManager:业务上层类,专门适配 HTTP/HTTPS,内置 GET/POST/PUT/DELETE 快捷方法,日常开发99%用它
五、AFNetworking 底层完整请求链路(源码级拆解)
以最常用的AFHTTPSessionManager GET请求为例,拆解从调用到响应的全底层流程。
Step1:初始化 Manager,全局唯一 Session
AFN 初始化 Manager 时,会全局创建一个 NSURLSession,所有请求共享同一个 Session,避免重复创建会话造成性能损耗。
同时初始化:请求序列化器、响应序列化器、安全策略、并发配置。
Step2:参数序列化,生成 NSURLRequest
AFN 自动通过AFHTTPRequestSerializer完成:
URL 拼接参数(GET)
Body 拼接 JSON/表单参数(POST)
自动设置请求头 Content-Type、User-Agent
统一超时时间、缓存策略
Step3:创建 DataTask,绑定代理 Delegate
这是 AFN 最精妙的设计:任务级代理转发
原生 NSURLSession 所有任务共用 Session 代理,无法区分不同任务回调;
AFN 为每一个 Task 单独绑定一个 AFURLSessionManagerTaskDelegate,实现:
不同请求互不干扰回调
精准进度回调、成功失败回调
任务结束自动销毁代理,杜绝内存泄漏
Step4:加入任务队列,控制并发
AFN 默认队列最大并发数为4,同一时间最多4个网络任务并行,其余任务排队串行执行,防止瞬间大量请求抢占线程、造成卡顿、超时。
Step5:resume 启动任务,底层走 NSURLSession 网络链路
最终依然调用原生[task resume],底层经过:DNS解析 → TCP握手 → TLS握手 → 加密传输 → 接收数据。
Step6:数据接收、自动反序列化
收到服务端数据后,AFN 通过AFHTTPResponseSerializer自动:
校验响应状态码(200~299 成功,其余自动判定失败)
自动 JSON 解析、数据转模型
捕获解析异常,统一回调错误信息
Step7:主线程回调结果
网络任务默认子线程执行,AFN 内部自动切回主线程回调 Block,开发者无需手动刷新UI线程,避免线程错乱崩溃。
六、高频实战案例:AFN 常用场景代码落地
案例1:基础 GET/POST 请求(标准封装)
// 初始化全局管理者 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/plain",@"text/html", nil]; manager.requestSerializer.timeoutInterval = 15; // GET 请求 [manager GET:@"https://httpbin.org/get" parameters:@{@"name":@"test"} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"GET成功:%@",responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"GET失败:%@",error); }]; // POST 请求 [manager POST:@"https://httpbin.org/post" parameters:@{@"age":@"18"} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"POST成功:%@",responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"POST失败:%@",error); }];案例2:文件上传(带进度回调)
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager POST:@"https://httpbin.org/post" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) { // 拼接上传文件 UIImage *image = [UIImage imageNamed:@"test"]; NSData *imageData = UIImagePNGRepresentation(image); [formData appendPartWithFileData:imageData name:@"file" fileName:@"test.png" mimeType:@"image/png"]; } progress:^(NSProgress * _Nonnull uploadProgress) { // 子线程回调上传进度 CGFloat progress = 1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount; NSLog(@"上传进度:%.2f",progress); } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"上传成功"); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"上传失败:%@",error); }];案例3:文件下载 + 断点续传
AFN 基于 DownloadTask 天然支持断点续传,暂停后再次请求可接续下载,无需自己处理数据偏移。
案例4:自定义请求头、Token 全局配置
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager.requestSerializer setValue:@"Bearer xxxxxxxx" forHTTPHeaderField:@"Authorization"]; [manager.requestSerializer setValue:@"iOS" forHTTPHeaderField:@"Client-Type"];案例5:HTTPS 证书配置(兼容上篇 HTTPS 原理)
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; // 开发环境允许非法证书(线上禁止) manager.securityPolicy.allowInvalidCertificates = YES; manager.securityPolicy.validatesDomainName = NO;七、核心底层重难点解析(解决90%疑难问题)
1. 为什么 AFN 不会内存泄漏?
很多人疑惑 Block 回调为什么不循环引用:
AFN 的 TaskDelegate 是临时绑定、任务结束立即销毁
Block 内部弱引用回调,任务完成后自动置空
Session 全局唯一,生命周期跟随 App,不存在泄漏风险
2. AFN 并发数为什么默认是4?
源于系统原生限制:HTTPMaximumConnectionsPerHost单域名最大并发连接数,系统默认6,AFN 优化为4,平衡速度与稳定性,防止并发过高导致服务器限流、请求超时、链路抢占。
3. 请求超时原理
AFN 设置的timeoutInterval本质是 NSURLRequest 的超时时间:从请求发起开始,15s 未完成数据传输直接判定超时。
注意:网络阻塞、DNS 解析慢、服务器卡顿都会触发超时。
4. 为什么后台下载必须用 Background 配置?
default 配置的 Session 在 App 退后台后会被系统挂起,任务暂停;background 配置可让系统托管任务,后台持续执行上传下载。
八、高频踩坑案例复盘(实战必看)
坑点1:请求超时、偶发请求失败
原因:多个页面共用同一个 Manager,并发队列拥堵、请求排队超时;全局超时时间过短。
解决:核心长接口单独创建 Manager,适当调大超时时间,控制并发数。
坑点2:响应数据解析失败(JSON 乱码/格式错误)
原因:AFN 默认只接收 JSON 格式,部分接口返回 text/html、text/plain,触发解析失败。
解决:手动添加可接收内容类型:
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",@"text/plain",@"charset=utf-8", nil];坑点3:重复请求导致数据错乱
原因:快速点击多次触发请求,多个 Task 同时执行,后返回的数据覆盖前数据。
解决:页面消失/请求新任务时,取消上一次 Task:[task cancel]。
坑点4:HTTPS 真机报错、模拟器正常
原因:真机严格证书校验,模拟器默认信任非法证书,与上篇 HTTPS 证书校验逻辑一致。
坑点5:上传大文件进度不动、卡顿
原因:文件数据一次性加载进内存,造成内存暴涨、主线程阻塞。
解决:使用文件路径上传,而非二进制 Data 上传,避免内存峰值过高。
九、面试高频必背问答(百分百命中)
1. AFNetworking 底层基于什么实现?为什么废弃 NSURLConnection?
AFN3.0+ 全系基于NSURLSession原生封装;NSURLConnection 老旧、不支持断点续传、后台任务、并发管理差、内存问题多,iOS9 已废弃,NSURLSession 性能与功能全面碾压。
2. AFHTTPSessionManager 和 AFURLSessionManager 区别?
AFURLSessionManager:底层通用基础类,封装 NSURLSession 核心能力,适配所有网络协议;AFHTTPSessionManager:继承自前者,专门适配 HTTP/HTTPS,封装常用 GET/POST 快捷方法,业务开发首选。
3. AFN 如何实现多任务回调隔离?
通过任务级代理绑定,为每一个 NSURLSessionTask 单独创建 TaskDelegate,替代原生 Session 全局代理,实现不同任务回调互不干扰。
4. AFN 默认并发数是多少?为什么?
默认最大并发 4,基于系统单域名连接限制,兼顾请求速度与服务器压力,避免高并发导致请求拥堵、超时、限流。
5. AFN Block 回调为什么不会内存泄漏?
AFN 采用临时任务代理模式,任务生命周期短,Block 无循环引用,任务结束后代理立即销毁,无内存堆积。
6. NSURLSession 的三种 Task 区别?
DataTask:短请求接口,内存接收数据;DownloadTask:文件下载,沙盒存储、支持断点续传、后台下载;UploadTask:文件上传,适配大文件、后台上传。
7. AFN 请求默认是串行还是并行?
默认最大4并行,超出排队串行,并非完全串行,也不是无限并行。
十、全文总结
1.底层本质:AFNetworking 是 NSURLSession 的工程级封装,无私有黑能力,所有网络能力均来自苹果原生 API。
2.核心优势:统一序列化、统一异常处理、任务隔离、并发控制、线程自动切换、证书安全封装、网络状态监听,极大简化原生复杂写法。
3.核心流程:共享Session → 参数序列化 → 绑定任务代理 → 队列调度 → 原生Task执行 → 自动解析 → 主线程回调。