AFNetworking
基于NSURLSession的封装。主要解决请求封装统一化,数据自动解析,多任务并发,线程调度和队列管理,网络状态监听。
AFURLSessionManager
对NSURLSession的封装。统一管理请求,回调,进度,响应序列化。
设计模式:
使用了模板方法模式,定义了统一的网络请求流程骨架,通过代理方法和block回调让子类或外部自定义细节。比如请求完成后的解析,进度回调等。
如何管理task和回调
- 根据NSURLRequset创建NSURLSessionDataTask
- 根据task创建AFURLSessionManagerTaskDelegate。delegate里包含这个task的progress,completionHandler以及responseSerializer
- 以taskID为key,delegate为value,存入字典里保存映射。
- 在收到urlsession task回调时,根据task找到delegate,交给AFURLSessionManagerTaskDelegate处理
- 在AFURLSessionManagerTaskDelegate中转为block,主线程返回。
线程安全
AFNetworking对mutableTaskDelegatesKeyedByTaskIdentifier的读写都用了nslock保证安全。
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, error);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
这里将所有成功失败收集到group中,后续可以通过group_notify统一收尾
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
__block NSArray *tasks = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
tasks = dataTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
tasks = uploadTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
tasks = downloadTasks;
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return tasks;
}
这里用了dispatch_semaphore加锁保证线程安全。
AFHTTPSessionManager
AFURLSessionManager的子类,针对GET,POST请求进一步封装。
AFURLRequestSerialiazation(response)
负责请求和响应的数据解析
设置好数据类型,比如JSON,XML,Image,请求完成后自动解析。
设计模式:
责任链模式。
依次遍历JSON,XML,Image,谁能处理水处理。
AFNetworkingReachabilityManager
实现网络状态变化监听。
设计模式:
单例模式。
AFImageDownloader
image+afnetworking里动态添加了AFImageDownloader(可以替换其他downloader)
image+afnetworking管理逻辑,最后调用AFImageDownloader下载
储存了当前的图片下载凭证,可以取消当前下载,
单次下载:
- 根据urlid判断此task是否已经存在
- 缓存相关
3.构建sessionmanager,进行下载
4.将回调handler绑定在mergedtask上
5.成功后遍历所有handler给回调
多个下载:
mergedtask小于最大并发数时直接开始并发下载,默认4。mergedtask.task resume
大于最大并发数进去queuedMergedTasks列表中
AFAutoPurgingImageCache
AFCachedImage
图片类。主要包含图片,唯一标识,容积,最近修改时间等
重写了get方法,每次获取iamge的时候都会更新当前时间作为最新访问时间。
提供两个协议:
1 图片处理协议:增删查 @protocol AFImageCache
2 网络协议:request相关 @protocol AFImageRequestCache
AFAutoPurgingImageCache: <AFImageRequestCache>
任务:数据校验,加入图片,ID管理,线程安全,容积管理。
缓存属性:缓存总容量,当前使用容量,用户偏好的清除后剩余容量。
初始化时指定了缓存总容量100,清理后的剩余容量60
加入图片:
加入图片使用dispatch_barrier_async+并发队列保证线程安全。
根据id获取之前缓存图片,如果之前有缓存,去掉缓存更新容积
存入新图片
在addimage的时候自动清理工具:
自动清理缓存方法使用了dispatch_barrier_async+并发队列保证线程安全。
1 总容量-清理后留存容量=目标清理容量。
2 缓存数据按照最后访问日期排序。
3 使用id删除图片
4 删除的图片记录容积,确定当前容积
常见问题
1. HTTPS双向认证
AFNetworking通过AFSecurityPolicy管理HTTPS的服务端证书校验,同时再AFURLSessionManager中通过实现didReceiveChallenge方法,支持HTTPS双向认证,在收到服务器的challenge时,读取本地p12证书,返回完成验证。
2. runloop
AFNetworking2.0基于NSURLConnection的封装会使用runloop进行子线程保活。但是AFNetworing3.0开始,基于NSURLSession的封装,其自身处理了runloop,所以不需要额外处理。
3. 线程安全
AFNetworking对mutableTaskDelegatesKeyedByTaskIdentifier的读写都用了nslock保证安全。
dispatch_semaphore_t 保证对self.session的task读取安全。
回调在主线程
AFAutoPurgingImageCache使用dispatch_barrier_async+并发队列保证线程安全.
// 读操作(并发)
- (UIImage *)imageForRequest:(NSURLRequest *)request {
__block UIImage *image;
dispatch_sync(self.synchronizationQueue, ^{
image = self.cachedImages[request.URL.absoluteString];
});
return image;
}
// 写操作(屏障)
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request {
dispatch_barrier_async(self.synchronizationQueue, ^{
self.cachedImages[request.URL.absoluteString] = image;
});
}
dispatch_sync的使用是由于需要立刻返回值。看起来时串行。但如果在不同线程里调用imageForRequest,实际上是并发的。dispatch_barrier_async可以保证写安全。
4. 缓存机制
AFNetworking 的缓存机制本质是对 NSURLCache 的封装,适合标准 HTTP 缓存场景。对于图片等特定资源,它提供了额外的内存缓存优化
5. 请求和响应序列化
AFJSONRequestSerializer
将参数序列化为 JSON 格式的请求体(Content-Type: application/json)
AFCompoundResponseSerializer
组合多个序列化器,按顺序尝试解析:AFJSONResponseSerializer,AFXMLParserResponseSerializer,AFImageResponseSerializer
6. 如何用 AFNetworking 实现文件上传和下载?
提供直接上传和分块上传(进度回调)。
支持断点续传
7.如何优化 AFNetworking 的请求性能?
AFHTTPSessionManager 封装后使用单例模式
进行配置:连接数,超时时间,设置缓存等
将耗时的数据解析放在子线程,比如sdwebimage的图片解码在子线程
8. AFNetworking 如何处理大量并发请求?
有最大的并发数限制,可以设置更改。有队列进行调度。可以设置优先级。
9.AFNetworking 和 NSURLSession 直接使用有什么区别?
内置序列化。
安全性
线程安全,自动回主线程
网络状态检测
错误封装,请求进度
YTKNetwok
在AFNetworking的基础上二次封装。
每个 API 封装为独立类,参数集中管理
自带链式调用和批量请求
支持requestInterceptor 和 responseInterceptor提供了统一的预处理和后处理能力,统一签名,日志,重试等逻辑。
SDWebimage
主流程分解
- URL 校验(sd_internalSetImageWithURL: 方法)。
- 内存缓存查询(SDImageCache 的 queryCacheOperationForKey:)。
- 磁盘缓存查询(通过 NSURLCache 或自定义磁盘路径)。
- 网络下载(SDWebImageDownloader 发起异步请求,支持并发队列、进度回调)。
- 图片解码(在后台线程通过 CGContextDrawImage 避免主线程卡顿)。
- 缓存写入(内存缓存 NSCache + 磁盘缓存异步存储)。
1. 如何避免重复下载
缓存机制。
下载去重:先判断是否已经有相同的请求了,如果有相同的请求就复用,把回调加到回调组里。如果没有再新建。
2. 黑名单机制
当一个url无效或者无法解析时,加入到黑名单里,下次直接返回失败,避免资源浪费。会在App重启时清除,也可以手动清除。
3. 与cell复用问题
cell会复用,快速滚动时会多次切换图片url,图片下载异步,容易出现图片没下载好,已经复用的情况。造成图片错位。
sdwebiamge的解决方案:统一imageview发起新的会把之前的取消,防止错误覆盖。
我们能做的优化: 设置sdwebiamge加载图片为低优先级,滚动时延迟加载。
或许可以自定义缓存路径,避免与其他缓存共用,提升查询命中率。