AFNetworking3.0学习笔记[更新中]
来源:互联网 发布:linux 8080端口被占用 编辑:程序博客网 时间:2024/05/23 21:50
9th,August,2016
概述
github地址
Github是这样介绍的:A delightful networking framework for iOS, OS X, watchOS, and tvOS。也就是说这是一款非常友好的第三方库,且适用于iOS,OS X,watchOS和tvOS平台。模块化结构,丰富的API,一款非常优秀的网络。
AFNetworking3.x的认识: 就是基于NSURLSession进行高度封装,给开发者提供更为友好的接口。
查看资料发现AFNetworking2.0与3.0区别还是蛮大的,iOS9.0中已经弃用NSURLConnection。因而AFNetworking3.0中没有对NSURLConnection的支持,而是基于NSURLSession进行封装。(ps: AFNetworking2.0则是基于NSURLConnection与NSOperation开发) 如果需从AFNetworking2.0迁移到3.0可以查看Github:AFNetworking 3.0 Migration Guide
1. AFHTTPSessionManager // 基于HTTP协议的会话管理器,继承AFURLSessionManager
2. AFNetworking
3. AFNetworkReachabilityManager // 网络可达性
4. AFSecurityPolicy // 安全性
5. AFURLRequestSerialization // 请求数据序列化
6. AFURLResponseSerialization // 响应数据序列化
7. AFURLSessionManager// 会话管理器,核心类
架构理解
from Draveness
苹果原生网络解决方案
在分析AFNetworking之前,先总结下苹果原生的网络解决方案。2003年跟着Safari一起推出的网络API:NSURLConnection,之后苹果重构了NSURLConnection,在2013年iOS7引入NSURLSession取代NSURLConnection,2015年iOS9弃用NSURLConnection。
NSURLConnection
从2003年开始,这套使用了十来年的API,虽然因代码简洁性一直被诟病。但在可扩展性与可组合性等方面表现的还是非常优秀的。NSURLConnection不单单只NSURLConnection这个组件,而是指一套构成URL加载系统的相互关联的组件:NSURLConnection,NSURLRequest,NSURLResponse,NSURLProtocol,NSURLCache,NSHTTPCookieStorage,NSURLCredentialStorage(证书存储)。
NSURLSession
同NSURLConnection,NSURLSession也是一组相互关联的组件:除了大部分与NSURLConnection相同的组件。NSURLSession类也是做了比较大的调整。NSURLConnection被调整为由NSURLSession,NSURLSessionConfiguration,以及NSURLSessionTask系列(包括NSURLSessionDataTask,NSURLSessionUploadTask,NSURLSessionDownloadTask以及iOS9推出的NSURLStreamTask)。
缓存策略
cachePolicy:
1、NSURLRequestUseProtocolCachePolicy 协议缓存,根据 response 中的 Cache-Control 字段判断缓存是否有效,如果缓存有效则使用缓存数据否则重新从服务器请求
2、NSURLRequestReloadIgnoringLocalCacheData 不使用缓存,直接请求新数据
3、NSURLRequestReloadIgnoringCacheData 等同于 NSURLRequestReloadIgnoringLocalCacheData
4、NSURLRequestReturnCacheDataElseLoad 直接使用缓存数据不管是否有效,没有缓存则重新请求
5、NSURLRequestReturnCacheDataDontLoad 直接使用缓存数据不管是否有效,没有缓存数据则失败
会话
NSURLSession 支持进程三种会话:
1、defaultSessionConfiguration:进程内会话(默认会话),用硬盘来缓存数据。
2、ephemeralSessionConfiguration:临时的进程内会话(内存),不会将 cookie、缓存储存到本地,只会放到内存中,当应用程序退出后数据也会消。
3、backgroundSessionConfiguration:后台会话,相比默认会话,该会话会在后台开启一个线程进行网络数据处理。
对比
苹果重构后的NSURLSession对开发者还是相对友好,也很简洁。如果没有特别依赖第三方库(AFNetworking)提供的功能,出于不需要依赖任何第三方库的考虑(依赖第三方库的成本还是有的),推荐使用原生API。
开始看源码啦
AFHTTPSessionManager
[[AFHTTPSessionManager alloc] initWithBaseURL:[[NSURL alloc] initWithString: TEST_URL]]
先看看调用栈,
// 从Draveness的github源码分析复制过来的- [AFHTTPSessionManager initWithBaseURL:] - [AFHTTPSessionManager initWithBaseURL:sessionConfiguration:] - [AFURLSessionManager initWithSessionConfiguration:] - [NSURLSession sessionWithConfiguration:delegate:delegateQueue:] - [AFJSONResponseSerializer serializer] // 负责序列化响应 - [AFSecurityPolicy defaultPolicy] // 负责身份认证 - [AFNetworkReachabilityManager sharedManager] // 查看网络连接情况 - [AFHTTPRequestSerializer serializer] // 负责序列化请求 - [AFJSONResponseSerializer serializer] // 负责序列化响应
初始化都做了哪些工作:
1. session会话配置初始化 // AFHTTPSessionManager
2. 序列化响应初始化 // AFRequestSerializer
3. 身份认证初始化,保证安全性 // AFSecurityPolicy
4. 网络连接情况初始化 // AFNetworkReachabilityManager
5. 序列化响应初始化 // AFResponseSerializer
发送请求
- 通过请求序列化获取请求NSMutableURLRequest;
- 调用父类方法
dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler
获取任务实例,并且通过response设置成功和失败的block
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress success:(void (^)(NSURLSessionDataTask *, id))success failure:(void (^)(NSURLSessionDataTask *, NSError *))failure{ NSError *serializationError = nil; NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; if (serializationError) { if (failure) { dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(nil, serializationError); }); } return nil; } __block NSURLSessionDataTask *dataTask = nil; dataTask = [self dataTaskWithRequest:request uploadProgress:uploadProgress downloadProgress:downloadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { if (error) { if (failure) { failure(dataTask, error); } } else { if (success) { success(dataTask, responseObject); } } }]; return dataTask;}
AFURLSessionManager
初始化方法
- NSURLSessionConfiguration默认为default类型,通过NSOperationQueue初始化设置操作队列,通过设置maxConcurrentOperationCount为1将操作队列设置成同步队列,初始化会话session时设置配置,代理,操作队列。
初始化响应序列化,安全策略。 mutableTaskDelegateKeyedByTaskIdentifier
字典初始化。这个字典时用来让每个task跟对应的代理建立映射。ps: AF对任务的代理进行了封装,转发给AF自定义的代理getTasksWithCompletionHandler
是NSURLSession自带的方法,用来异步获取当前没有完成的任务。初始化时参数中的数组为空,但如果是从后台回到前台,则数组就不一定为空了。
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { self = [super init]; if (!self) { return nil; } if (!configuration) { configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; } self.sessionConfiguration = configuration; self.operationQueue = [[NSOperationQueue alloc] init]; self.operationQueue.maxConcurrentOperationCount = 1; self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; self.responseSerializer = [AFJSONResponseSerializer serializer]; self.securityPolicy = [AFSecurityPolicy defaultPolicy];#if !TARGET_OS_WATCH self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];#endif self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init]; self.lock = [[NSLock alloc] init]; self.lock.name = AFURLSessionManagerLockName; [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { for (NSURLSessionDataTask *task in dataTasks) { [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil]; } for (NSURLSessionUploadTask *uploadTask in uploadTasks) { [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil]; } for (NSURLSessionDownloadTask *downloadTask in downloadTasks) { [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil]; } }]; return self;}
获取任务实例
- 通过请求创建任务实例dataTask。dataTask是在
url_session_manager_create_task_safely
这个block中创建,目的是为了适配iOS8以下,创建session时,偶发出现session属性taskIdentifier值不唯一的情况。 addDelegateForDataTask
给该任务实例添加数据代理。
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler { __block NSURLSessionDataTask *dataTask = nil; url_session_manager_create_task_safely(^{ dataTask = [self.session dataTaskWithRequest:request]; }); [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler]; return dataTask;}
原生代理转发
didCompleteWithError
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error{ AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; // delegate may be nil when completing a task in the background if (delegate) { [delegate URLSession:session task:task didCompleteWithError:error]; [self removeDelegateForTask:task]; } if (self.taskDidComplete) { self.taskDidComplete(session, task, error); }}
didReceiveData
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; [delegate URLSession:session dataTask:dataTask didReceiveData:data]; if (self.dataTaskDidReceiveData) { self.dataTaskDidReceiveData(session, dataTask, data); }}
AFURLResponseSerialization
处理响应的模块,将请求返回的数据解析成对应的格式。
首先声明AFURLResponseSerialization是协议,该文件内所有的类都遵循该协议。AFHTTPResponseSerializer为根类,其他(如AFJSONResponseSerializer,AFXMLParserResponseSerializer等)都是继承AFHTTPResponseSerializer。
初始化方法:
- (instancetype)init { ... # 初始化 self.stringEncoding = NSUTF8StringEncoding;// 设置为UTF8字符编码 self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];// 设置有效状态码 self.acceptableContentTypes = nil;// 初始化里未设置接收的内容类型,代表不限制接收内容类型 return self;}
验证响应的有效性
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
AFURLRequestSerialization
修改请求(主要是 HTTP 请求)的头部,提供了一些语义明确的接口设置 HTTP 头部字段。
获取请求
- 通过url实例化NSMutableURLRequest,并设置请求类型。
- 遍历
AFHTTPRequestSerializerObservedKeyPaths
数组(该数组存放的是NSURLReqeust的一些属性),通过mutableObservedChangedKeyPaths
集合(初始化时会对该属性进行重置并添加对AFHTTPRequestSerializerObservedKeyPaths
中属性的观察,一旦观察到值被设置就添加到mutableObservedChangedKeyPaths
集合中)中如果存在该键值,则将属性设置给request。 - 通过调用
requestBySerializingRequest
方法将参数添加到原有请求上返回一个对参数进行编码的新请求。
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters error:(NSError *__autoreleasing *)error{ NSParameterAssert(method); NSParameterAssert(URLString); NSURL *url = [NSURL URLWithString:URLString]; NSParameterAssert(url); NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url]; mutableRequest.HTTPMethod = method; for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) { [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath]; } } mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy]; return mutableRequest;}
对参数进行编码
- 从
HTTPRequestHeaders
字典中进行遍历,如果旧请求中未设置该header的值,则在新请求中设置该header。 - 将参数从数组/字典/集合转化为字符串,具体的转化方式可以自定义(设置了
queryStringSerialization
属性),也可以使用AFNetworking默认的方式。 - 根据请求类型,将参数设置到请求中。
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error{ NSParameterAssert(request); NSMutableURLRequest *mutableRequest = [request mutableCopy]; [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }]; NSString *query = nil; if (parameters) { if (self.queryStringSerialization) { NSError *serializationError; query = self.queryStringSerialization(request, parameters, &serializationError); if (serializationError) { if (error) { *error = serializationError; } return nil; } } else { switch (self.queryStringSerializationStyle) { case AFHTTPRequestQueryStringDefaultStyle: query = AFQueryStringFromParameters(parameters); break; } } } if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { if (query && query.length > 0) { mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]]; } } else { // #2864: an empty string is a valid x-www-form-urlencoded payload if (!query) { query = @""; } if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; } [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]]; } return mutableRequest;}
AFNetworkingReachabilityManager
监测网络的可达性,基于SCNetworkReachabilityRef类进行开发。
类中的私有方法可以写成static void functionName() {} 这种C函数格式。
keyPathsForValuesAffectingValueForKey // 注册键值依赖
参考:AFNetworking 3.0 源码解读(一)之 AFNetworkReachabilityManager
AFSecurityPolicy
在发起HTTPS连接时,验证证书是否正确。
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) { AFSSLPinningModeNone,// 无条件信任服务器证书 AFSSLPinningModePublicKey,// 对服务器返回的证书进行公钥验签 AFSSLPinningModeCertificate,// 服务器返回的证书与本地证书进行比对校验};
核心方法
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(nullable NSString *)domain;
小结
- AFNetworking1.0基于NSURLConnection封装。AFNetworking2.0提供了基于NSURLConnection的API与基于NSURLSession的API,而在AFNetworking3.0中由于苹果在iOS9.0弃用NSURLConnection,所以相应的在3.0中也移除了对NSURLConnection的支持。 AFNetworking2.0依赖NSURLConnection和NSOperation,AFNetworking3.0依赖NSURLSession.
ZA
Tip
- 初始化AFURLSessionManager或者AFHTTPSessionManager时,如果NSURLSessionConfiguration为Default类型,则无需再进行配置,因为框架中默认就是设置为defaultSessionConfiguration。
报错
- 报错:“module ‘AFNetworking’ not found“
解决方法:User Header Search Paths is set to $(SRCROOT)/Pods and is recursive
from : stackoverflow-use_frameworks! and Model not found build error
参考资料
AFNetworking源码解读资料
- Draveness源码分析
通过简单的调用AFNetworking发送请求的代码,查看调用栈作为入口了解整个框架的架构。
并分析AFURLSessionManager,AFURLSerialization,AFNetworkReachabilityManager以及验证HTTPS证书。了解每个部分是如何工作以及各个部分又是如何有机组合在一起。 - Bang源码分析
Bang的源码侧重于细节,分析了其中使用的一些hack等。 马在路上源码分析
itangqi源码分析
在分析一种介绍了AFNetworking2.0与AFNetworking3.0的区别,大体上的资料来自于github/AFNetworking提供的2.0到3.0的迁移指南。二中正式开始分析,也是从整体框架开始分析,有点像Draveness的思路。- 涂耀辉源码解读
其他相关参考资料
AFNetworking 概述(一)
AFNetworking 2.0-发布于2013年9月16日
AFNetworking 3.0 源码阅读笔记(一)
AFNetworking 3.0 Migration Guide
浅析 iOS 应用网络层设计
NSURLSession 网络库 - 原生系统送给我们的礼物
log:
26th,March,2017
- AFNetworking3.0学习笔记[更新中]
- AFNetworking3.0
- AFNetWorking3.0
- AFNetworking3.0
- AFNetworking3.0+
- ios中afnetworking3.0网络请求
- sed学习笔记 更新中...
- Ant学习笔记(更新中~)
- clojure学习笔记(更新中)
- 数据库学习笔记(更新中)
- SourceInsight学习笔记,更新中
- 学习笔记,持续更新中
- ACE学习笔记--持续更新中
- lua学习笔记(持续更新中)
- c++ primer学习笔记(更新中)
- ACE学习笔记--持续更新中
- FVWM学习笔记(更新中...20090423...)
- 《maven权威指南》学习笔记(更新中)
- 杭电-1287 破译密码 (异或运算)
- Ehcache——设置缓存的大小
- IOI集训论文集
- POJ 3020 Antenna Placement
- Xcode 7 设置 LaunchImage图片
- AFNetworking3.0学习笔记[更新中]
- DataGridView中CellFormatting事件的应用
- 做UE的软件
- 根据Matrix获取Rotation
- 几种常见的博弈
- 前端冷知识
- OpenCV+ Python
- DP之最长不降子序列类问题
- 导出Excel方式汇总-- 第一种