源码阅读:AFNetworking(十)——AFNetworkActivityIndicatorManager

1,020 阅读8分钟

该文章阅读的AFNetworking的版本为3.2.0。

这个类就是控制在网络请求时在状态栏左上角转动的网络活动指示器的显现与隐藏。

1.接口文件

1.1.宏

NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.")

一上来我们可以看到有这样一个宏,经过查阅,这个宏的意思是,这个类在扩展中不可用。这个扩展是iOS8的新特性,其他app可以与扩展进行数据交换。

1.2.属性

/**
 网络活动指示器是否启用
 */
@property (nonatomic, assign, getter = isEnabled) BOOL enabled;

/**
 网络活动指示器是否显示
*/
@property (readonly, nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;

/**
 网络活动指示器显示延时,默认是网络请求开始后1秒
 */
@property (nonatomic, assign) NSTimeInterval activationDelay;

/**
 网络活动指示器隐藏延时,默认是网络请求结束后0.17秒
 */

@property (nonatomic, assign) NSTimeInterval completionDelay;

1.3.方法

/**
 获取网络活动指示器单例
 */
+ (instancetype)sharedManager;

/**
 增加活动的网络请求的数量
 */
- (void)incrementActivityCount;

/**
 减少活动的网络请求的数量
 */
- (void)decrementActivityCount;

/**
 设置网络活动指示器隐藏和显示时的自定义事件
 */
- (void)setNetworkingActivityActionWithBlock:(nullable void (^)(BOOL networkActivityIndicatorVisible))block;

2.实现文件

2.1.枚举

typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
    AFNetworkActivityManagerStateNotActive,
    AFNetworkActivityManagerStateDelayingStart,
    AFNetworkActivityManagerStateActive,
    AFNetworkActivityManagerStateDelayingEnd
};

这个枚举定义了网络活动指示器的状态:

AFNetworkActivityManagerStateNotActive表示网络活动指示器处于非活动状态 AFNetworkActivityManagerStateDelayingStart表示网络活动指示器处于延时开始状态 AFNetworkActivityManagerStateActive表示网络活动指示器处于活动状态 AFNetworkActivityManagerStateDelayingEnd表示网络活动指示器处于延时结束状态

2.2.静态常量

/**
 定义了开始延时时间,为1秒
 */
static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0;

/**
 定义了结束延时时间,为0.17秒
 */
static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17;

2.3.静态方法

/**
 这个方法用户获取通知中的网络请求对象
 */
static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) {
    if ([[notification object] respondsToSelector:@selector(originalRequest)]) {
        return [(NSURLSessionTask *)[notification object] originalRequest];
    } else {
        return nil;
    }
}

2.4.别名

/**
 定义了网络状态发生变化时的回调block
 */
typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisible);

2.5.类扩展

2.5.1.属性

/**
 活动请求数量
 */
@property (readwrite, nonatomic, assign) NSInteger activityCount;

/**
 开始延时计时器
 */
@property (readwrite, nonatomic, strong) NSTimer *activationDelayTimer;

/**
 结束延时计时器
 */
@property (readwrite, nonatomic, strong) NSTimer *completionDelayTimer;

/**
 是否正在活动状态
 */
@property (readonly, nonatomic, getter = isNetworkActivityOccurring) BOOL networkActivityOccurring;

/**
 网络状态发生变化时的回调block
 */
@property (nonatomic, copy) AFNetworkActivityActionBlock networkActivityActionBlock;

/**
 当前状态
 */
@property (nonatomic, assign) AFNetworkActivityManagerState currentState;

/**
 网络活动指示器是否显示
 */
@property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;

2.5.2.方法

/**
 根据当前的状态改变网络活动指示器的状态
 */
- (void)updateCurrentStateForNetworkActivityChange;

2.6.方法实现

  • 生命周期方法
+ (instancetype)sharedManager {
    static AFNetworkActivityIndicatorManager *_sharedManager = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedManager = [[self alloc] init];
    });

    return _sharedManager;
}

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }
    // 记录当前状态是非活动状态
    self.currentState = AFNetworkActivityManagerStateNotActive;
    // 监听了AFURLSessionManager的三个通知,分别是任务已经开始、任务已经暂停和任务已经结束
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil];
    // 为开始和结束延时时间赋值
    self.activationDelay = kDefaultAFNetworkActivityManagerActivationDelay;
    self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay;

    return self;
}

- (void)dealloc {
    // 移除对通知的观察
    [[NSNotificationCenter defaultCenter] removeObserver:self];

    // 结束计时器对象
    [_activationDelayTimer invalidate];
    [_completionDelayTimer invalidate];
}
  • 公共方法
- (void)setEnabled:(BOOL)enabled {
    _enabled = enabled;
    // 如果设置为NO,就把网络活动指示器的状态设置为非活动状态
    if (enabled == NO) {
        [self setCurrentState:AFNetworkActivityManagerStateNotActive];
    }
}

- (void)setNetworkingActivityActionWithBlock:(void (^)(BOOL networkActivityIndicatorVisible))block {
    // 记录传入的block
    self.networkActivityActionBlock = block;
}

- (BOOL)isNetworkActivityOccurring {
    // 加锁获取网络请求数量,大于0就是正在活动状态
    @synchronized(self) {
        return self.activityCount > 0;
    }
}

- (void)setNetworkActivityIndicatorVisible:(BOOL)networkActivityIndicatorVisible {
    // 如果新老数据不一致
    if (_networkActivityIndicatorVisible != networkActivityIndicatorVisible) {
        // 手动实现networkActivityIndicatorVisible属性的KVO方法
        [self willChangeValueForKey:@"networkActivityIndicatorVisible"];
        // 加锁赋值
        @synchronized(self) {
             _networkActivityIndicatorVisible = networkActivityIndicatorVisible;
        }
        [self didChangeValueForKey:@"networkActivityIndicatorVisible"];
        if (self.networkActivityActionBlock) {
            // 如果设置了回调block就调用
            self.networkActivityActionBlock(networkActivityIndicatorVisible);
        } else {
            // 如果没有设置回调block就直接设置网络活动指示器的显示状态
            [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible];
        }
    }
}

- (void)setActivityCount:(NSInteger)activityCount {
    // 加锁赋值
	@synchronized(self) {
		_activityCount = activityCount;
	}

    // 主队列异步调用
    dispatch_async(dispatch_get_main_queue(), ^{
        // 更新当前网络状态
        [self updateCurrentStateForNetworkActivityChange];
    });
}

- (void)incrementActivityCount {
    // 手动实现activityCount属性的KVO方法
    [self willChangeValueForKey:@"activityCount"];
    // 加锁赋值
	@synchronized(self) {
		_activityCount++;
	}
    [self didChangeValueForKey:@"activityCount"];
    
    // 主队列异步调用更新当前网络状态
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateCurrentStateForNetworkActivityChange];
    });
}

- (void)decrementActivityCount {
    // 手动实现activityCount属性的KVO方法
    [self willChangeValueForKey:@"activityCount"];
    // 加锁赋值
	@synchronized(self) {
	    // 不能小于零
		_activityCount = MAX(_activityCount - 1, 0);
	}
    [self didChangeValueForKey:@"activityCount"];

    // 主队列异步调用更新当前网络状态
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateCurrentStateForNetworkActivityChange];
    });
}
  • 私有方法
- (void)networkRequestDidStart:(NSNotification *)notification {
    // 接收到任务开始的通知如果请求对象中有URL就增加请求活动数量
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        [self incrementActivityCount];
    }
}

- (void)networkRequestDidFinish:(NSNotification *)notification {
    // 接收到任务结束的通知如果请求对象中有URL就减少请求活动数量
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        [self decrementActivityCount];
    }
}

- (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
    // 加锁保护
    @synchronized(self) {
        // 如果新老数据不一致
        if (_currentState != currentState) {
            // 手动实现currentState属性的KVO方法
            [self willChangeValueForKey:@"currentState"];
            // 赋值
            _currentState = currentState;
            switch (currentState) {
                // 如果设置的是无活动
                case AFNetworkActivityManagerStateNotActive:
                    // 取消开始和完成延时计时器
                    [self cancelActivationDelayTimer];
                    [self cancelCompletionDelayTimer];
                    // 隐藏网络活动指示器
                    [self setNetworkActivityIndicatorVisible:NO];
                    break;
                // 如果设置的是延时开始
                case AFNetworkActivityManagerStateDelayingStart:
                    // 开始开始延时计时
                    [self startActivationDelayTimer];
                    break;
                // 如果设置的是开始
                case AFNetworkActivityManagerStateActive:
                    // 取消完成延时计时器
                    [self cancelCompletionDelayTimer];
                    // 显示网络活动指示器
                    [self setNetworkActivityIndicatorVisible:YES];
                    break;
                // 如果设置的是延时结束
                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;
        }
    }
}

- (void)startActivationDelayTimer {
    // 设置开始延时计时器并加入到运行循环中
    self.activationDelayTimer = [NSTimer
                                 timerWithTimeInterval:self.activationDelay target:self selector:@selector(activationDelayTimerFired) userInfo:nil repeats:NO];
    [[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes];
}

- (void)activationDelayTimerFired {
    // 如果当前有网络活动
    if (self.networkActivityOccurring) {
        // 就设置状态为活动
        [self setCurrentState:AFNetworkActivityManagerStateActive];
    // 如果当前无网络活动
    } else {
        // 就设置状态为非活动
        [self setCurrentState:AFNetworkActivityManagerStateNotActive];
    }
}

- (void)startCompletionDelayTimer {
    // 先使之前的计时器无效
    [self.completionDelayTimer invalidate];
    // 设置结束延时计时器并加入到运行循环中
    self.completionDelayTimer = [NSTimer timerWithTimeInterval:self.completionDelay target:self selector:@selector(completionDelayTimerFired) userInfo:nil repeats:NO];
    [[NSRunLoop mainRunLoop] addTimer:self.completionDelayTimer forMode:NSRunLoopCommonModes];
}

- (void)completionDelayTimerFired {
    // 设置状态为非活动
    [self setCurrentState:AFNetworkActivityManagerStateNotActive];
}

- (void)cancelActivationDelayTimer {
    // 使开始延时计时器无效
    [self.activationDelayTimer invalidate];
}

- (void)cancelCompletionDelayTimer {
    // 使完成延时计时器无效
    [self.completionDelayTimer invalidate];
}

3.总结

看完了代码,我们可以梳理一下AFNetworkActivityIndicatorManager类的工作流程:

  • 显示网络活动指示器

1.通过在初始化方法中注册通知监听AFNetworkingtask的开始、暂停和结束。

2.当接收到task开始的通知时,就会在通知的回调方法中记录当前网络请求活动数量,手动发送KOV,然后调用更新状态方法。

3.在更新状态方法中,如果当前的状态是非活动,并且有网络请求活动,就会将当前状态设置为延时开始状态。

4.在currentState属性的setter中,先手动发送KVO,如果发现设置的状态为开始延时状态,就会开启开始延时计时器。

5.在1秒过后就会触发计时器方法,在计时器方法中,如果发现当前依然有网络请求在进行中,就将当前状态设置为活动状态。但是如果当前已经没有进行中的网络请求了,就会把状态设置为非活动状态。

6.这时就又回到了重写的currentState属性的setter中,依旧是先手动发送KVO,如果发现设置的状态为开始状态,就结束掉完成延时计时器,并显示网络活动指示器。

  • 隐藏网络活动指示器

7.当接收到task结束的通知时,同样的会在通知的回调方法中记录当前网络请求活动数量,手动发送KOV,然后调用更新状态方法。

8.在更新状态方法中,如果当前的状态是活动,并且已经没有进行中的网络请求了,就会将当前状态设置为延时结束状态。

9.在重写的currentState属性setter中,除了手动发送KVO,如果发现设置的状态为延时结束状态,就会开启完成延时计时器。

10.在0.17秒过后,触发计时器方法,计时器方法中会将状态设置为非活动状态,在currentState的setter中,先手动发送KVO,在非活动状态下就会结束掉开始和完成延时计时器,并隐藏网络活动指示器

源码阅读系列:AFNetworking

源码阅读:AFNetworking(一)——从使用入手

源码阅读:AFNetworking(二)——AFURLRequestSerialization

源码阅读:AFNetworking(三)——AFURLResponseSerialization

源码阅读:AFNetworking(四)——AFSecurityPolicy

源码阅读:AFNetworking(五)——AFNetworkReachabilityManager

源码阅读:AFNetworking(六)——AFURLSessionManager

源码阅读:AFNetworking(七)——AFHTTPSessionManager

源码阅读:AFNetworking(八)——AFAutoPurgingImageCache

源码阅读:AFNetworking(九)——AFImageDownloader

源码阅读:AFNetworking(十)——AFNetworkActivityIndicatorManager

源码阅读:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking

源码阅读:AFNetworking(十二)——UIButton+AFNetworking

源码阅读:AFNetworking(十三)——UIImageView+AFNetworking

源码阅读:AFNetworking(十四)——UIProgressView+AFNetworking

源码阅读:AFNetworking(十五)——UIRefreshControl+AFNetworking

源码阅读:AFNetworking(十六)——UIWebView+AFNetworking