AFNetworking 3.0 源碼解讀(一)之 AFNetworkReachabilityManager

此系列文章都是轉(zhuǎn)載文章 ? ?文章出處


做ios開發(fā)藕各,AFNetworking 這個網(wǎng)絡(luò)框架肯定都非常熟悉萎河,也許我們平時只使用了它的部分功能臊岸,而且我們對它的實現(xiàn)原理并不是很清楚橙数,就好像總是有一團迷霧在眼前一樣。

接下來我們就非常詳細的來讀一讀這個框架的代碼帅戒,我們的目標(biāo)就是理解了它的思想之后商模,能夠明白我們的請求是如何實現(xiàn)的,我們的代碼哪里還需要進行改進,如果能夠更進一步施流,我們能夠總結(jié)出一套適合大部分應(yīng)用的網(wǎng)絡(luò)架構(gòu)思想响疚。

能夠讓一些人從中受益。

我們先來看看整個框架的文件系統(tǒng)瞪醋,我們先不對每個文件的作用進行說明忿晕,在整個源碼解讀最后的一篇中我們會對整個框架進行總結(jié)。會有一張清晰的圖表來說明這個問題银受。

我們在看一個框架的時候呢践盼,可以這樣先看,先看每個文件的頭文件宾巍,也就是.h文件

可以看到咕幻,有的頭文件是包含了別的頭文件的,在不考慮系統(tǒng)的頭文件的情況下顶霞,我們能夠發(fā)現(xiàn)一些比較獨立的類肄程,從上圖中,我們可以看出

比較獨立的類有:

1.AFURLResponseSerialization.h

2.AFNetworkReachabilityManager.h

3.AFURLRequestSerialization.h

4.AFSecurityPolicy.h

本篇就介紹AFNetworkReachabilityManager.h的內(nèi)容选浑,這個是用來監(jiān)控網(wǎng)絡(luò)環(huán)境變化的類蓝厌。

#import

通過導(dǎo)入了這個頭文件,我們得知:網(wǎng)絡(luò)監(jiān)控的實現(xiàn)是依賴SystemConfiguration這個api的古徒。說明這個api能夠提供這樣的功能拓提,至少讓我們明白了我們平時都會導(dǎo)入它的一個用途。

這是一個枚舉封裝隧膘,還是遵循一個使用枚舉的原則代态,當(dāng)滿足一個有限的并具有統(tǒng)一主題的集合的時候,我們就考慮枚舉疹吃。在這里作者是枚舉了4種類型胆数。這幾種類型能夠滿足我們開發(fā)中大部分的功能,如果不滿足互墓,可以自行進行擴展。

NS_ASSUME_NONNULL_BEGIN

NS_ASSUME_NONNULL_END

這個是為了swift的可選類型配添加的蒋搜,在這兩個終點的內(nèi)容的參數(shù)默認都是nonnull的篡撵。

這段文字是對這個類的說明。我們估且不去管它說了什么豆挽,在看看蘋果官方的

*** 這樣的內(nèi)容會出現(xiàn)在一個屬性或者方法的上方育谬,目的是對其內(nèi)容的解釋。我看到這里就想到了我們平時的開發(fā)帮哈,我們能夠把每段代碼都當(dāng)成是api的開發(fā)膛檀,也把注釋寫的詳細一點。曾經(jīng)看過兩種不同的說辭,一種是說把代碼注釋盡量少些咖刃,要求代碼簡介可讀性強泳炉。另一種是說注釋要詳細,著重考慮他人讀代碼的感受嚎杨。個人感覺還是寫詳細一點比較好花鹅,因為可能過一段時間之后,自己再去看自己當(dāng)時寫的代碼可能就不記得了枫浙。很有可能在寫這些繁瑣的注釋的過程中刨肃,能夠想到些什么,比如如何合并掉一些沒必要的方法等等箩帚。

本類提供了四個只讀的屬性來讓我們獲取我們需要的內(nèi)容

1. 網(wǎng)絡(luò)狀態(tài)

2. 是否是可達的

3. 當(dāng)前連接是否是WWAN

4. 當(dāng)前連接是夠是WiFi

四個屬性均為只讀屬性真友,只給了用戶訪問權(quán),注意BOOL屬性一般是要寫getter方法的紧帕。

作者使用了這個來分隔同一類中不同功能模塊盔然。這個算是個人習(xí)慣問題吧。舉個平時開發(fā)的例子焕参,在.m文件中我個人使用#pragma mark 分隔不同功能轻纪。

提供了5中初始化方法,能夠滿足大部分的需求叠纷。

SCNetworkReachabilityRef 這個很重要刻帚,這個類的就是基于它開發(fā)的。

+ (instancetype)managerForDomain:(NSString*)domain; 監(jiān)聽制定domain的網(wǎng)絡(luò)狀態(tài)涩嚣。

+ (instancetype)managerForAddress:(constvoid*)address; 監(jiān)聽某個socket地址的網(wǎng)絡(luò)狀態(tài)崇众,socket通信請看這篇文章:socket通信

打開和關(guān)閉監(jiān)聽的方法。

返回一個網(wǎng)絡(luò)狀態(tài)的本地語言的字符串航厚。往往我們可以根據(jù)這個字符串來告訴用戶顷歌,當(dāng)前網(wǎng)絡(luò)發(fā)生了什么,當(dāng)然幔睬,也可以根據(jù)狀態(tài)自定義提示文字眯漩。

設(shè)置網(wǎng)絡(luò)轉(zhuǎn)態(tài)改變的回調(diào),監(jiān)聽網(wǎng)絡(luò)改變的回調(diào)有兩種方式:

1.使用上邊的這個方法麻顶。

2.監(jiān)聽AFNetworkingReachabilityDidChangeNotification通知赦抖。

這個是與網(wǎng)絡(luò)狀態(tài)變化相關(guān)的通知。接受的通知中會有一個userinfo 是一個NSDictionary 其中key就是

AFNetworkingReachabilityNotificationStatusItem

*** 這簡單的兩行代碼能夠告訴我們的是辅肾,我們平時的開發(fā)中 但凡設(shè)計到發(fā)通知的功能队萤,我們應(yīng)該把通知的字符串封裝到一個專有的文件中,同時在文件內(nèi)部按不同模塊進行區(qū)分矫钓,當(dāng)然必要的注釋也很有必要要尔。

ps:FOUNDATION_EXPORT 和#define 都能定義常量舍杜。FOUNDATION_EXPORT 能夠使用==進行判斷,效率略高赵辕。而且能夠隱藏定義細節(jié)(就是實現(xiàn)部分不在.中)

對函數(shù):根據(jù)狀態(tài)獲取字符串 ?聲明既绩。

好了,這個類的.h文件我們已經(jīng)非常相信的進行解讀了匆帚,我們并不是大概的說了下他提供的功能熬词,而是通過讀每行代碼,我們能聯(lián)想到什么吸重,什么東西能幫助我們更好的編程互拾。

我們接著看AFNetworkReachabilityManager.m 的內(nèi)容

這幾個頭文件是系統(tǒng)庫,是為了后邊的sockaddr_in6 /sockaddr_in 準(zhǔn)備的嚎幸,不熟悉的可以看這篇文章socket通信

這幾個就沒什么好說的了颜矿,我們接著看

這個方法是對.h 中最后一個方法的實現(xiàn)。指的我們注意的是NSLocalizedStringFromTable這個宏嫉晶。為什么要注意它呢骑疆?

這就涉及到本地國際化的問題。所謂的國際化就是讓你的app能夠根據(jù)不同的語言顯示相對應(yīng)的語言替废。

*** 但這并不簡單箍铭,沒有經(jīng)驗的開發(fā)人員,一開始可能不會做這樣的設(shè)置椎镣,如果日后需要國際話了诈火,在做就很麻煩了。所以說在開中状答,但凡使用到字符串的地方都要考慮語言的不同冷守。不同的語言下,一個意思的表達所使用的字符串長度是不一樣的惊科,這就影射出空間的寬度可能會不一樣拍摇。

好了,國際化的內(nèi)容就不說了馆截,請自行搜索充活。

1/**2*? 根據(jù)SCNetworkReachabilityFlags這個網(wǎng)絡(luò)標(biāo)記來轉(zhuǎn)換成我們在開發(fā)中經(jīng)常使用的網(wǎng)絡(luò)狀態(tài)31.不能連接網(wǎng)絡(luò)42.蜂窩連接53.WiFi連接64.未知連接7*/8staticAFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {910//是否能夠到達11BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) !=0);1213//在聯(lián)網(wǎng)之前需要建立連接14BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) !=0);1516//是否可以自動連接17BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) !=0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) !=0));1819//是否可以連接,在不需要用戶手動設(shè)置的前提下20BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) ==0);2122//是否可以聯(lián)網(wǎng)的條件 1.能夠到達 2.不需要建立連接或者不需要用戶手動設(shè)置連接 就表示能夠連接到網(wǎng)絡(luò)23BOOL isNetworkReachable = (isReachable && (!needsConnection ||canConnectWithoutUserInteraction));2425AFNetworkReachabilityStatus status =AFNetworkReachabilityStatusUnknown;26if(isNetworkReachable ==NO) {27status =AFNetworkReachabilityStatusNotReachable;28}29#ifTARGET_OS_IPHONE30elseif((flags & kSCNetworkReachabilityFlagsIsWWAN) !=0) {31status =AFNetworkReachabilityStatusReachableViaWWAN;32}33#endif34else{35status =AFNetworkReachabilityStatusReachableViaWiFi;36}3738returnstatus;39}

這個方法根據(jù)SCNetworkReachabilityFlags這個標(biāo)記轉(zhuǎn)換成我們自定義的枚舉類型蜡娶。至于轉(zhuǎn)換規(guī)則混卵,上邊的代碼中注釋部分寫的很清楚。

*** 在這里不得不多說幾句翎蹈,很多框架中都會把一個類中的私有方法寫成這樣。為什么呢男公? 我們在開發(fā)中經(jīng)常會寫成- (void)funcName; 這樣的私有方法荤堪。

我個人的意見是一個類中的私有方法寫成static void funcName() 這樣的c函數(shù)比較好合陵。

1. 在文件的最前方,比較容易查找

2. 可以適當(dāng)?shù)氖褂脙?nèi)聯(lián)函數(shù)澄阳,提高效率拥知。

根據(jù)一個標(biāo)識 來處理Block和通知。保證兩者同一狀態(tài)碎赢。

need-to-insert-img

包含了 類中需要處理的屬性低剔。

need-to-insert-img

來看這個最基本的初始化方法,初始化了自身的屬性肮塞。

CFRetain()后要記得CFRelease().

need-to-insert-img

通過一個socket地址來初始化襟齿。 首先新建SCNetworkReachabilityRef 對象,然后調(diào)用initWithReachability: 方法枕赵。記得手動管理內(nèi)存猜欺。

need-to-insert-img

這個方法基本同上。

綜合上邊兩個方法拷窜,我們發(fā)現(xiàn)?SCNetworkReachabilityRef 有兩個創(chuàng)建方法:

1.SCNetworkReachabilityCreateWithName

2.SCNetworkReachabilityCreateWithAddress

need-to-insert-img

由于IPv6 是ios9和os_x 10.11后邊推出的开皿,所有要進行版本判斷。這禮拜呢設(shè)計到的socket的知識篮昧,請看socket通信

通過這段代碼我們能學(xué)到什么呢赋荆?

1,方法的創(chuàng)建也是有順序的懊昨,可以使用函數(shù)訪問函數(shù)的思想窄潭。

2. @if 這樣的預(yù)編譯指令能夠替換掉代碼中部分if else 。好處就是代碼會不會被編譯的區(qū)別疚颊。

need-to-insert-img

單例的寫法狈孔。

need-to-insert-img

對需要釋放時,做一些處理材义。

need-to-insert-img

這個是.h文件暴露出來的3個BOOL 屬性的getter方法均抽,注意,由于我們在@property中定義了getter方法其掂,所以getter方法就要寫成我們定義的那種油挥。

從這3個方法中也能看出,函數(shù)嵌套的思想還是很重要款熬,要想做到這一點深寥,只能是多想才行。

need-to-insert-img

這個算是這個類的核心方法贤牛,設(shè)置監(jiān)聽網(wǎng)咯監(jiān)聽惋鹅。

我們先來了解下基礎(chǔ)知識。

SCNetworkReachabilityContext

點進去殉簸,會發(fā)現(xiàn)這是一個結(jié)構(gòu)體闰集,一般c語言的結(jié)構(gòu)體是對要保存的數(shù)據(jù)的一種描述

need-to-insert-img

1. 第一個參數(shù)接受一個signedlong 的參數(shù)

2. 第二個參數(shù)接受一個void * 類型的值沽讹,相當(dāng)于oc的id類型,void * 可以指向任何類型的參數(shù)

3. 第三個參數(shù) 是一個函數(shù) 目的是對info做retain操作武鲁,

4. 第四個參數(shù)是一個函數(shù)爽雄,目的是對info做release操作

5. 第五個參數(shù)是 一個函數(shù),根據(jù)info獲取Description字符串

在這里我們要攜帶的這個info就是下邊的這個block

need-to-insert-img

1__weak __typeof(self)weakSelf =self;2AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {3__strong __typeof(weakSelf)strongSelf =weakSelf;45strongSelf.networkReachabilityStatus =status;6if(strongSelf.networkReachabilityStatusBlock) {7strongSelf.networkReachabilityStatusBlock(status);8}910};

need-to-insert-img

retain和release 函數(shù)是下邊的這兩個函數(shù)

need-to-insert-img

1staticconstvoid* AFNetworkReachabilityRetainCallback(constvoid*info) {2returnBlock_copy(info);3}45staticvoidAFNetworkReachabilityReleaseCallback(constvoid*info) {6if(info) {7Block_release(info);8}9}

need-to-insert-img

設(shè)置網(wǎng)絡(luò)監(jiān)控分為下邊幾個步驟:

1.我們先新建上下文

1SCNetworkReachabilityContext context = {0, (__bridgevoid*)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};

2.設(shè)置回調(diào)

1SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);

其中這個AFNetworkReachabilityCallback 是這樣被定義的一個函數(shù)

typedefvoid(*SCNetworkReachabilityCallBack)? ? (

SCNetworkReachabilityRef? ? ? ? ? ? target,

SCNetworkReachabilityFlags? ? ? ? ? ? flags,void*__nullable? ? info

);

在本類中

1staticvoidAFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags,void*info) {2AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);3}

3.加入RunLoop池

1SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

其中CFRunLoopGetMain()代表主RunLoop

ok沐鼠,差不多已經(jīng)完成

need-to-insert-img

在異步線程 發(fā)送一次當(dāng)前的網(wǎng)絡(luò)狀態(tài)挚瘟。

need-to-insert-img

停止網(wǎng)絡(luò)監(jiān)控

need-to-insert-img

這兩個方法沒什么好說的了,一個是getter 一個是setter

need-to-insert-img

注冊鍵值依賴饲梭,這個可能大家平時用的比較少乘盖。可以了解一下

比如說一個類User中有兩個屬性

need-to-insert-img

還有一個卡片的類card

need-to-insert-img

我們寫一個info的setter 和 getter ?方法排拷,

need-to-insert-img

need-to-insert-img

1@interfaceUser :NSObject2@property (nonatomic,copy)NSString *name;3@property (nonatomic,assign)NSUInteger age;4@end5678@interfacecard :NSObject9@property (nonatomic,copy)NSString *info;10@property (nonatomic,strong)User *user;11@end12@implementationcard1314- (NSString *)info {15return[NSString stringWithFormat:@"%@/%lu",_user.name,(unsignedlong)_user.age];16}17- (void)setInfo:(NSString *)info {1819NSArray *array = [info componentsSeparatedByString:@"/"];20_user.name = array[0];21_user.age = [array[1] integerValue];2223}2425+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {26NSSet * keyPaths =[super keyPathsForValuesAffectingValueForKey:key];27NSArray * moreKeyPaths =nil;2829if([key isEqualToString:@"info"])30{31moreKeyPaths = [NSArray arrayWithObjects:@"user.name",@"user.age", nil];32}3334if(moreKeyPaths)35{36keyPaths =[keyPaths setByAddingObjectsFromArray:moreKeyPaths];37}3839returnkeyPaths;40}4142@end

need-to-insert-img

代碼差不多就是上邊的侧漓。我們可以監(jiān)聽card的info屬性,當(dāng)user中的name或者age的值發(fā)生改變的時候监氢,就會觸發(fā)info的鍵值監(jiān)聽方法布蔗。這就是鍵值依賴的作用。

好了 本篇文章就到此為止了浪腐。下一篇會是AFSecurityPolicy

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纵揍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子议街,更是在濱河造成了極大的恐慌泽谨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件特漩,死亡現(xiàn)場離奇詭異吧雹,居然都是意外死亡,警方通過查閱死者的電腦和手機涂身,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門雄卷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蛤售,你說我怎么就攤上這事丁鹉。” “怎么了悴能?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵揣钦,是天一觀的道長。 經(jīng)常有香客問我漠酿,道長冯凹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任炒嘲,我火速辦了婚禮宇姚,結(jié)果婚禮上团驱,老公的妹妹穿的比我還像新娘。我一直安慰自己空凸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布寸痢。 她就那樣靜靜地躺著呀洲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪啼止。 梳的紋絲不亂的頭發(fā)上道逗,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音献烦,去河邊找鬼滓窍。 笑死,一個胖子當(dāng)著我的面吹牛巩那,可吹牛的內(nèi)容都是我干的吏夯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼即横,長吁一口氣:“原來是場噩夢啊……” “哼噪生!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起东囚,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤跺嗽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后页藻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桨嫁,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年份帐,在試婚紗的時候發(fā)現(xiàn)自己被綠了璃吧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡弥鹦,死狀恐怖肚逸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情彬坏,我是刑警寧澤朦促,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站栓始,受9級特大地震影響务冕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幻赚,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一禀忆、第九天 我趴在偏房一處隱蔽的房頂上張望臊旭。 院中可真熱鬧,春花似錦箩退、人聲如沸离熏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滋戳。三九已至,卻和暖如春啥刻,著一層夾襖步出監(jiān)牢的瞬間奸鸯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工可帽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娄涩,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓映跟,卻偏偏與公主長得像蓄拣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子努隙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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