源碼閱讀:AFNetworking(十)——AFNetworkActivityIndicatorManager

該文章閱讀的AFNetworking的版本爲3.2.0。bash

這個類就是控制在網絡請求時在狀態欄左上角轉動的網絡活動指示器的顯現與隱藏。網絡

1.接口文件

1.1.宏

NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.")
複製代碼

一上來咱們能夠看到有這樣一個宏,通過查閱,這個宏的意思是,這個類在擴展中不可用。這個擴展是iOS8的新特性,其餘app能夠與擴展進行數據交換。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表示網絡活動指示器處於延時結束狀態async

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類的工做流程:oop

  • 顯示網絡活動指示器

1.經過在初始化方法中註冊通知監聽AFNetworkingtask的開始、暫停和結束。post

2.當接收到task開始的通知時,就會在通知的回調方法中記錄當前網絡請求活動數量,手動發送KOV,而後調用更新狀態方法。ui

3.在更新狀態方法中,若是當前的狀態是非活動,而且有網絡請求活動,就會將當前狀態設置爲延時開始狀態。atom

4.在currentState屬性的setter中,先手動發送KVO,若是發現設置的狀態爲開始延時狀態,就會開啓開始延時計時器。spa

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

相關文章
相關標籤/搜索