大概在两个月以前阅读了AFN的2.x的源代码,因为项目中一直使用的2.x,这几天抽空把3.x的代码补上.第一篇笔记记录AFN的demo,有了demo就知道如何用这个库,能够掌握业务知识,然后再深入学习底层的源码,能够站在不一样的角度去看待一些问题.
Delegate中的内容
首先在AppDelegate中有如下代码,其中NSURLCache
和AFNetworkActivityIndicatorManager
两个类需要学习
NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
NSURLCache
NSURLCache 中提到NSURLCache 为您的应用的 URL 请求提供了内存中以及磁盘上的综合缓存机制. 作为基础类库 URL 加载系统 的一部分,任何通过 NSURLConnection/NSURLSession加载的请求都将被 NSURLCache 处理.当一个请求完成下载来自服务器的回应,一个缓存的回应将在本地保存。下一次同一个请求再发起时,本地保存的回应就会马上返回,不需要连接服务器。NSURLCache会自动且透明地返回响应,具体的缓存策略由客户端和服务端共同协商搞定.
在我们发出的请求NSURLRequest中会有一个cachePolicy
属性,它就是客户端在发出请求时设定的缓存策略.具体有几种模式,可以参考官方文档,以下表格表示实际中常用的几个策略以及其真实含义:
枚举 | 含义 |
---|---|
UseProtocolCachePolicy | 默认行为 |
ReloadIgnoringLocalCacheData | 不使用缓存 |
ReturnCacheDataElseLoad | 使用缓存(不管它是否过期)如果缓存中没有,就从网络加载 |
ReturnCacheDataDontLoad | 离线模式:使用缓存(不管它是否过期),但是不从网络加载 |
AFNetworkActivityIndicatorManager维护的状态机
这个类是AFN的中监听网络状态的类.主要根据当前是否有请求管理status bar
上的activity indicator
的显示与关闭.
AFNetworkActivityIndicatorManager
会维护一个状态机,记录当前网络框架中是否有请求,并通过activityCount
属性维护当前同时的session请求的个数来决定是否在status bar
显示菊花.
typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
AFNetworkActivityManagerStateNotActive,
AFNetworkActivityManagerStateDelayingStart,
AFNetworkActivityManagerStateActive,
AFNetworkActivityManagerStateDelayingEnd
};
Demo中给了一个很好的示例,在app启动完成以后直接调用[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]
监听菊花的控制,默认情况下并未监听.
状态机的核心方法如下:
#pragma mark - Internal State Management
- (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
@synchronized(self) {//设置状态需要加锁
if (_currentState != currentState) {
[self willChangeValueForKey:@"currentState"];
_currentState = currentState;
switch (currentState) {
//初始化状态,需要重置重要参数的状态
case AFNetworkActivityManagerStateNotActive:
[self cancelActivationDelayTimer];
[self cancelCompletionDelayTimer];
[self setNetworkActivityIndicatorVisible:NO];
break;
//转换成delay开始状态->这里有个延迟显示的问题
case AFNetworkActivityManagerStateDelayingStart:
[self startActivationDelayTimer];
break;
//转换成正在active状态,菊花可见
case AFNetworkActivityManagerStateActive:
[self cancelCompletionDelayTimer];
[self setNetworkActivityIndicatorVisible:YES];
break;
//转换成delay结束状态->delay time以后状态会被设置成NotActive
case AFNetworkActivityManagerStateDelayingEnd:
[self startCompletionDelayTimer];
break;
}
[self didChangeValueForKey:@"currentState"];
}
}
}
- (void)updateCurrentStateForNetworkActivityChange {
if (self.enabled) {
switch (self.currentState) {
case AFNetworkActivityManagerStateNotActive:
if (self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateDelayingStart];
}
break;
case AFNetworkActivityManagerStateDelayingStart:
//No op. Let the delay timer finish out.
break;
case AFNetworkActivityManagerStateActive:
if (!self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateDelayingEnd];
}
break;
case AFNetworkActivityManagerStateDelayingEnd:
if (self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateActive];
}
break;
}
}
}
在监听广播收到AFNetworkingTaskDidResumeNotification
,AFNetworkingTaskDidSuspendNotification
,AFNetworkingTaskDidResumeNotification
等Notification时,就会调用incrementActivityCount
,decrementActivityCount
方法对_activityCount
进行改变并且调用updateCurrentStateForNetworkActivityChange
方法改变状态.
其他值得学习的地方
timer使用commomMode
将timer加到NSRunLoopCommonModes
中可以在任何时候都能保证timer的运行
[[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes];
.h使用readonly,.m可以修改
该类中有属性networkActivityIndicatorVisible
,如果需要外部访问是readonly
而内部可以修改.可以参考下面做法:
// .h中
@property (readonly, nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
//.m中
@property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
AFNetworking中的几个通知
也许在其他地方也用得着这几个通知
AFNetworkingTaskDidResumeNotification
AFNetworkingTaskDidSuspendNotification
AFNetworkingTaskDidCompleteNotification
在demo中调用了[self.refreshControl setRefreshingWithStateOfTask:task]
这样一个方法.通过源码可以发现正式用了这几个通知控制refresh的开始和停止刷新.
- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
if (task) {
UIRefreshControl *refreshControl = self.refreshControl;
if (task.state == NSURLSessionTaskStateRunning) {
[refreshControl beginRefreshing];
[notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingTaskDidResumeNotification object:task];
[notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidCompleteNotification object:task];
[notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidSuspendNotification object:task];
} else {
[refreshControl endRefreshing];
}
}
}