AFNetworking源碼探究(十八) —— UIKit相關(guān)之AFNetworkActivityIndicatorManager(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.03.03

前言

我們做APP發(fā)起網(wǎng)絡(luò)請(qǐng)求趣些,都離不開一個(gè)非常有用的框架AFNetworking,可以說這個(gè)框架的知名度已經(jīng)超過了蘋果的底層網(wǎng)絡(luò)請(qǐng)求部分深碱,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請(qǐng)求的芍锚,但是一定知道AFNetworking,接下來幾篇我們就一起詳細(xì)的解析一下這個(gè)框架扁瓢。感興趣的可以看上面寫的幾篇。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請(qǐng)求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)
3. AFNetworking源碼探究(三) —— GET請(qǐng)求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(一)
4. AFNetworking源碼探究(四) —— GET請(qǐng)求實(shí)現(xiàn)之代理轉(zhuǎn)發(fā)思想(一)
5. AFNetworking源碼探究(五) —— AFURLSessionManager中NSURLSessionDelegate詳細(xì)解析(一)
6. AFNetworking源碼探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate詳細(xì)解析(一)
7. AFNetworking源碼探究(七) —— AFURLSessionManager中NSURLSessionDataDelegate詳細(xì)解析(一)
8. AFNetworking源碼探究(八) —— AFURLSessionManager中NSURLSessionDownloadDelegate詳細(xì)解析(一)
9. AFNetworking源碼探究(九) —— AFURLSessionManagerTaskDelegate中三個(gè)轉(zhuǎn)發(fā)代理方法詳細(xì)解析(一)
10. AFNetworking源碼探究(十) —— 數(shù)據(jù)解析之?dāng)?shù)據(jù)解析架構(gòu)的分析(一)
11. AFNetworking源碼探究(十一) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(二)
12. AFNetworking源碼探究(十二) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(三)
13. AFNetworking源碼探究(十三) —— AFSecurityPolicy與安全認(rèn)證 (一)
14. AFNetworking源碼探究(十四) —— AFSecurityPolicy與安全認(rèn)證 (二)
15. AFNetworking源碼探究(十五) —— 請(qǐng)求序列化之架構(gòu)分析(一)
16. AFNetworking源碼探究(十六) —— 請(qǐng)求序列化之協(xié)議方法的實(shí)現(xiàn)(二)
17. AFNetworking源碼探究(十七) —— _AFURLSessionTaskSwizzling實(shí)現(xiàn)方法交換(轉(zhuǎn)載)(一)

回顧

上一篇主要講述了_AFURLSessionTaskSwizzling用于方法交換补君,接下來幾篇講述AFN與UIKit相關(guān)的部分引几。


UIKit相關(guān)的類

下面我們看一下UIKit相關(guān)的類。

可以看見還是很多關(guān)于UIKit的類,都是在原類上的擴(kuò)展伟桅。下面我們就看一下這幾個(gè)相關(guān)的類敞掘。


AFNetworkActivityIndicatorManager

這個(gè)就是網(wǎng)絡(luò)請(qǐng)求時(shí)候上面旋轉(zhuǎn)的小菊花。

1. 使用

#import "AFNetworkActivityIndicatorManager.h"

[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];

AFNetworkActivityIndicatorManager管理狀態(tài)欄中網(wǎng)絡(luò)活動(dòng)指示器的狀態(tài)楣铁。 啟用后玖雁,它將偵聽指示會(huì)話任務(wù)已啟動(dòng)或完成的通知,并相應(yīng)地啟動(dòng)或停止對(duì)指示器進(jìn)行動(dòng)畫處理盖腕。 活動(dòng)請(qǐng)求的數(shù)量增加和減少很像堆椇斩或信號(hào)量,只要該數(shù)量大于零溃列,活動(dòng)指示器就會(huì)動(dòng)畫劲厌。

當(dāng)您的應(yīng)用程序完成啟動(dòng)時(shí),您應(yīng)該啟用AFNetworkActivityIndicatorManager的共享實(shí)例听隐。 在AppDelegate應(yīng)用程序中:didFinishLaunchingWithOptions:你可以用下面的代碼來完成:

[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];

通過為sharedManager設(shè)置enabledYES补鼻,當(dāng)請(qǐng)求開始和結(jié)束時(shí),網(wǎng)絡(luò)活動(dòng)指示器將自動(dòng)顯示并隱藏雅任。 你不需要自己調(diào)用incrementActivityCountdecrementActivityCount风范。

2. 指示器的狀態(tài)

下面看一下指示器的幾個(gè)狀態(tài)。

typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
    //沒有請(qǐng)求
    AFNetworkActivityManagerStateNotActive,
    //請(qǐng)求延遲開始
    AFNetworkActivityManagerStateDelayingStart,
    //請(qǐng)求進(jìn)行中
    AFNetworkActivityManagerStateActive,
    //請(qǐng)求延遲結(jié)束
    AFNetworkActivityManagerStateDelayingEnd
};

這里包括四個(gè)狀態(tài)沪么,包括請(qǐng)求硼婿、結(jié)束、延遲開始和延遲結(jié)束成玫。這里可能延遲開始和延遲結(jié)束大家需要注意下加酵。如果一個(gè)請(qǐng)求時(shí)間很短,那么菊花很可能閃一下就結(jié)束了哭当。如果很多請(qǐng)求過來猪腕,那么菊花會(huì)不停的閃啊閃,這顯然并不是我們想要的效果钦勘。所以設(shè)置了這兩個(gè)狀態(tài)參數(shù)陋葡,在一個(gè)請(qǐng)求開始的時(shí)候,延遲一會(huì)在去轉(zhuǎn)菊花彻采,如果在這延遲時(shí)間內(nèi)腐缤,請(qǐng)求結(jié)束了,那么我就不需要去轉(zhuǎn)菊花了肛响。但是一旦轉(zhuǎn)菊花開始岭粤,哪怕很短請(qǐng)求就結(jié)束了,我們還是會(huì)去轉(zhuǎn)一個(gè)時(shí)間再去結(jié)束特笋,這時(shí)間就是延遲結(jié)束的時(shí)間剃浇。

3. 初始化方法

下面看一下初始化方法。

+ (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;
    }
    //設(shè)置狀態(tài)為沒有request活躍
    self.currentState = AFNetworkActivityManagerStateNotActive;
    //開始下載通知
    [[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;
    //結(jié)束延遲
    self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay;
    return self;
}

// 延遲時(shí)間設(shè)置
static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0;
static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17;

初始化方法里面有三個(gè)通知監(jiān)聽,監(jiān)聽了三個(gè)通知虎囚,用來監(jiān)聽當(dāng)前正在進(jìn)行的網(wǎng)絡(luò)請(qǐng)求的狀態(tài)角塑。

下面我們就看這兩個(gè)通知方法的實(shí)現(xiàn)。

//請(qǐng)求開始
- (void)networkRequestDidStart:(NSNotification *)notification {
    
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        //增加請(qǐng)求活躍數(shù)
        [self incrementActivityCount];
    }
}

//請(qǐng)求結(jié)束
- (void)networkRequestDidFinish:(NSNotification *)notification {
    //AFNetworkRequestFromNotification(notification)返回這個(gè)通知的request,用來判斷request是否是有效的
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        //減少請(qǐng)求活躍數(shù)
        [self decrementActivityCount];
    }
}

還記得我前面說過的淘讥,活動(dòng)指示器是如何出現(xiàn)的嗎圃伶?活動(dòng)請(qǐng)求的數(shù)量增加和減少很像堆棧或信號(hào)量蒲列,只要該數(shù)量大于零窒朋,活動(dòng)指示器就會(huì)動(dòng)畫。

下面看一下活動(dòng)指示器活動(dòng)請(qǐng)求數(shù)量的增加還是減少數(shù)量的計(jì)算蝗岖。

//請(qǐng)求開始
- (void)networkRequestDidStart:(NSNotification *)notification {
    
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        //增加請(qǐng)求活躍數(shù)
        [self incrementActivityCount];
    }
}

//請(qǐng)求結(jié)束
- (void)networkRequestDidFinish:(NSNotification *)notification {
    //AFNetworkRequestFromNotification(notification)返回這個(gè)通知的request,用來判斷request是否是有效的
    if ([AFNetworkRequestFromNotification(notification) URL]) {
        //減少請(qǐng)求活躍數(shù)
        [self decrementActivityCount];
    }
}
//增加請(qǐng)求活躍數(shù)
- (void)incrementActivityCount {
    
    //活躍的網(wǎng)絡(luò)數(shù)+1炼邀,并手動(dòng)發(fā)送KVO
    [self willChangeValueForKey:@"activityCount"];
    @synchronized(self) {
        _activityCount++;
    }
    [self didChangeValueForKey:@"activityCount"];

    //主線程去做
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateCurrentStateForNetworkActivityChange];
    });
}

//減少請(qǐng)求活躍數(shù)
- (void)decrementActivityCount {
    [self willChangeValueForKey:@"activityCount"];
    @synchronized(self) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
        _activityCount = MAX(_activityCount - 1, 0);
#pragma clang diagnostic pop
    }
    [self didChangeValueForKey:@"activityCount"];

    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateCurrentStateForNetworkActivityChange];
    });
}

后面需要用下面的方法判斷是否是活躍的

//判斷是否活躍
- (BOOL)isNetworkActivityOccurring {
    @synchronized(self) {
        return self.activityCount > 0;
    }
}

下面看一個(gè)類的核心方法。

// 設(shè)置當(dāng)前小菊花狀態(tài)

- (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
    @synchronized(self) {
        if (_currentState != currentState) {
            //KVO
            [self willChangeValueForKey:@"currentState"];
            _currentState = currentState;
            switch (currentState) {
                //如果為不活躍
                case AFNetworkActivityManagerStateNotActive:
                    //取消兩個(gè)延遲用的timer
                    [self cancelActivationDelayTimer];
                    [self cancelCompletionDelayTimer];
                    //設(shè)置小菊花不可見
                    [self setNetworkActivityIndicatorVisible:NO];
                    break;
                case AFNetworkActivityManagerStateDelayingStart:
                    //開啟一個(gè)定時(shí)器延遲去轉(zhuǎn)菊花
                    [self startActivationDelayTimer];
                    break;
                    //如果是活躍狀態(tài)
                case AFNetworkActivityManagerStateActive:
                    //取消延遲完成的timer
                    [self cancelCompletionDelayTimer];
                    //開始轉(zhuǎn)菊花
                    [self setNetworkActivityIndicatorVisible:YES];
                    break;
                    //延遲完成狀態(tài)
                case AFNetworkActivityManagerStateDelayingEnd:
                    //開啟延遲完成timer
                    [self startCompletionDelayTimer];
                    break;
            }
        }
        [self didChangeValueForKey:@"currentState"];
    }
}

這里重寫了狀態(tài)的setter方法剪侮,這里根據(jù)當(dāng)前狀態(tài),是否需要開始執(zhí)行一個(gè)延遲開始或者延遲完成洛退,又或者是否需要取消這兩個(gè)延遲瓣俯。

后記

本篇主要介紹了AFNetworkActivityIndicatorManager這個(gè)與UIKit相關(guān)的類,后面會(huì)繼續(xù)帶著大家看后面的幾個(gè)類兵怯。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末彩匕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子媒区,更是在濱河造成了極大的恐慌驼仪,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袜漩,死亡現(xiàn)場離奇詭異绪爸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)宙攻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門奠货,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人座掘,你說我怎么就攤上這事递惋。” “怎么了溢陪?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵萍虽,是天一觀的道長。 經(jīng)常有香客問我形真,道長杉编,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮王财,結(jié)果婚禮上卵迂,老公的妹妹穿的比我還像新娘。我一直安慰自己绒净,他們只是感情好见咒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挂疆,像睡著了一般改览。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缤言,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天宝当,我揣著相機(jī)與錄音,去河邊找鬼胆萧。 笑死庆揩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的跌穗。 我是一名探鬼主播订晌,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蚌吸!你這毒婦竟也來了锈拨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤羹唠,失蹤者是張志新(化名)和其女友劉穎奕枢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佩微,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缝彬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喊衫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跌造。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖族购,靈堂內(nèi)的尸體忽然破棺而出壳贪,到底是詐尸還是另有隱情,我是刑警寧澤寝杖,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布违施,位于F島的核電站,受9級(jí)特大地震影響瑟幕,放射性物質(zhì)發(fā)生泄漏磕蒲。R本人自食惡果不足惜留潦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辣往。 院中可真熱鬧兔院,春花似錦、人聲如沸站削。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽许起。三九已至十偶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間园细,已是汗流浹背惦积。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猛频,地道東北人狮崩。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像鹿寻,于是被迫代替她去往敵國和親厉亏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容