參拜一下AFNetworking的源碼兴喂。
第四篇源碼、暫時(shí)來(lái)看也是iOS方向的最后一篇焚志、擼完準(zhǔn)備趁著熱乎擼一擼網(wǎng)絡(luò)協(xié)議衣迷。
目錄
準(zhǔn)備工作
功能模塊
-
AFURLSessionManager/AFHTTPSessionManager
- 核心代碼
- 一些比較有意思的東西
- 在監(jiān)聽(tīng)屬性的時(shí)候、可以用NSStringFromSelector(@selector(xxx))這種方式來(lái)自動(dòng)提示娩嚼。
- 功能AIP分層
- 如何防止block循環(huán)引用
- 把NSURLSession眾多代理轉(zhuǎn)化成了block
- 消除編譯器clang警告
- 正則的簡(jiǎn)便寫法
- 如何做到對(duì)外只讀蘑险、對(duì)內(nèi)讀寫
-
AFNetworkReachabilityManager
- 核心代碼
- 四種網(wǎng)絡(luò)狀態(tài)
- 開(kāi)始暫停
- 狀態(tài)改變的回調(diào)block
- 知識(shí)點(diǎn)
- 關(guān)于FOUNDATION_EXPORT和UIKIT_EXTERN的選擇
- .#if - #esle - #endif
- 注冊(cè)鍵值依賴
- 核心代碼
-
AFSecurityPolicy
- 核心代碼
- .cer文件在iOS里如何使用的
- 三種驗(yàn)證模式
- 知識(shí)點(diǎn)
- __Require_Quiet判斷
- 核心代碼
AFHTTPRequestSerializer
-
AFHTTPResponseSerializer
- 核心代碼
- AFURLResponseSerialization協(xié)議以及其解碼方法
- 知識(shí)點(diǎn)
- 協(xié)議的應(yīng)用
- 如何在一個(gè)方法中返回兩個(gè)NSError
- NSIndexSet對(duì)象
- 服務(wù)器返回的圖片是壓縮過(guò)的
- 核心代碼
參考資料
準(zhǔn)備工作
GitHub
使用版本3.1.0
PODS:
- AFNetworking (3.1.0):
- AFNetworking/NSURLSession (= 3.1.0)
- AFNetworking/Reachability (= 3.1.0)
- AFNetworking/Security (= 3.1.0)
- AFNetworking/Serialization (= 3.1.0)
- AFNetworking/UIKit (= 3.1.0)
- AFNetworking/NSURLSession (3.1.0):
- AFNetworking/Reachability
- AFNetworking/Security
- AFNetworking/Serialization
- AFNetworking/Reachability (3.1.0)
- AFNetworking/Security (3.1.0)
- AFNetworking/Serialization (3.1.0)
- AFNetworking/UIKit (3.1.0):
- AFNetworking/NSURLSession
DEPENDENCIES:
- AFNetworking
SPEC CHECKSUMS:
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
PODFILE CHECKSUM: 75e1e619317fd130ee494d35ddff3d9c614c4390
COCOAPODS: 1.3.1
推薦在看AFN之前、先了解一下NSURLSession
不然感覺(jué)會(huì)看的一頭霧水岳悟、也體會(huì)不到AFN的偉大之處
《iOS基礎(chǔ)深入補(bǔ)完計(jì)劃--網(wǎng)絡(luò)模塊NSURLSession概述》
功能模塊
除了這四個(gè)服務(wù)性模塊之外佃迄、UIKit文件夾下基本是對(duì)各種UI控件的擴(kuò)展泼差。
AFURLSessionManager/AFHTTPSessionManager
承接了主要的網(wǎng)絡(luò)傳輸任務(wù)、實(shí)現(xiàn)了NSURLSession絕大部分的代理方法呵俏。
-
核心代碼
一些比較有意思的東西
-
在監(jiān)聽(tīng)屬性的時(shí)候堆缘、可以用
NSStringFromSelector(@selector(xxx))
這種方式來(lái)自動(dòng)提示。
因?yàn)閷傩员旧砭褪桥c其get方法同名普碎、可以降低出錯(cuò)概率吼肥。
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
-
功能AIP分層
AFURLSessionManager
實(shí)現(xiàn)了所有的NSURLSessionDelegate
。
但同時(shí)又將其中某些需要處理復(fù)雜邏輯的代理傳遞給了AFURLSessionManagerTaskDelegate
麻车。
使得代碼更清晰缀皱、邏輯更明確。
需要注意的是动猬、AFURLSessionManagerTaskDelegate
完全包裹在了AFURLSessionManager
內(nèi)部啤斗、外界完全感受到他的存在。但是又能做數(shù)據(jù)處理赁咙、這個(gè)架構(gòu)設(shè)計(jì)真心很贊钮莲。
除此之外、AFURLSessionManager
與AFHTTPSessionManager
之間也做了很好的分層彼水。
你可以單獨(dú)使用AFURLSessionManager
進(jìn)行網(wǎng)絡(luò)會(huì)話崔拥、也可以通過(guò)AFHTTPSessionManager
更好的使用AFURLSessionManager
進(jìn)行HTTP請(qǐng)求。
-
如何防止block循環(huán)引用
其實(shí)我?guī)啄昵熬吐?tīng)說(shuō)AFN可以防止循環(huán)引用凤覆、但是一直沒(méi)看链瓦。
今天找了找發(fā)現(xiàn)似乎已經(jīng)沒(méi)有了這段代碼
所以個(gè)人推測(cè)現(xiàn)在不會(huì)引起循環(huán)引用的原因、應(yīng)該是因?yàn)锳FN都在作為單例使用叛赚、和self并不互相持有澡绩。
貼一段以前別人帖子里的代碼:
//復(fù)寫setCompletionBlock
- (void)setCompletionBlock:(void (^)(void))block {
[self.lock lock];
if (!block) {
[super setCompletionBlock:nil];
} else {
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//看有沒(méi)有自定義的完成組,否則用AF的組
dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
//看有沒(méi)有自定義的完成queue俺附,否則用主隊(duì)列
dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
//調(diào)用設(shè)置的Block,在這個(gè)組和隊(duì)列中
dispatch_group_async(group, queue, ^{
block();
});
//結(jié)束時(shí)候置nil,防止循環(huán)引用
dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];
}
[self.lock unlock];
}
-
把NSURLSession眾多代理轉(zhuǎn)化成了block
這個(gè)說(shuō)實(shí)話我并不太暫停...
個(gè)人感覺(jué)block就是應(yīng)該控制個(gè)數(shù)溪掀、而NSURLSession的代理加起來(lái)起碼有二三十個(gè)事镣。
如果到了這種數(shù)量級(jí)的數(shù)據(jù)傳遞、真的還是用代理吧揪胃、饒了我璃哟。
-
消除編譯器clang警告
其中Wgnu可以換成其他具體命令
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
#pragma clang diagnostic pop
-
正則的簡(jiǎn)便寫法
講道理我還真第一次見(jiàn)
`A ?: B = A ? A : B`
-
如何做到對(duì)外只讀、對(duì)內(nèi)讀寫
.h中
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
.m中
@property (readwrite, nonatomic, strong) NSURL *baseURL;
AFNetworkReachabilityManager
AFN中負(fù)責(zé)網(wǎng)絡(luò)狀態(tài)模塊喊递。在不同的網(wǎng)絡(luò)狀態(tài)下可以監(jiān)聽(tīng)随闪、或者實(shí)時(shí)查詢、并且需要手動(dòng)開(kāi)啟或者關(guān)閉骚勘。
-
四種網(wǎng)絡(luò)狀態(tài)
未知铐伴、無(wú)網(wǎng)絡(luò)撮奏、運(yùn)營(yíng)商網(wǎng)絡(luò)、WiFi網(wǎng)絡(luò)
-
開(kāi)始暫停
-
狀態(tài)改變的回調(diào)block
代碼不多当宴、詳情可參閱《iOS源碼補(bǔ)完計(jì)劃--AFNetworking(二)》
知識(shí)點(diǎn)
-
關(guān)于FOUNDATION_EXPORT和UIKIT_EXTERN的選擇
都可以代替宏來(lái)定義常量
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
有人說(shuō)是如果文件基于FOUNDATION則用前者畜吊、反之則用后者。
二者都能替代#define户矢、并且通過(guò)地址比對(duì)常量(也就是可以通過(guò) == 直接進(jìn)行比較)玲献、效率更高。
-
#if - #esle - #endif
#ifdef __IPHONE_11_0
//對(duì)應(yīng)代碼
#endif
用普通的if-else也是一樣梯浪、好處就是在編譯階段是否會(huì)被編譯捌年。
不過(guò)、#if - #esle - #endif不能用來(lái)判斷一個(gè)動(dòng)態(tài)的語(yǔ)法挂洛。
-
注冊(cè)鍵值依賴
KVO的一個(gè)冷門方法
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
return [NSSet setWithObject:@"networkReachabilityStatus"];
}
return [super keyPathsForValuesAffectingValueForKey:key];
}
當(dāng)return的 值被改變的時(shí)候延窜、觸發(fā)key的監(jiān)聽(tīng)
也就是說(shuō)當(dāng)networkReachabilityStatus
改變的時(shí)候、reachable
/reachableViaWWAN
/reachableViaWiFi
的KVO監(jiān)聽(tīng)都將被觸發(fā)
AFSecurityPolicy
負(fù)責(zé)網(wǎng)絡(luò)安全策略(證書)的驗(yàn)證模塊
核心代碼
-
.cer文件在iOS里如何使用的
整個(gè)驗(yàn)證都是基于SecTrustRef
的抹锄、和.cer
文件的關(guān)系大概是:
NSData格式的證書
==>SecCertificateRef
==>SecTrustRef對(duì)象
而SecTrustRef
逆瑞、就是一個(gè)內(nèi)部至少攜帶了證書與公鑰的結(jié)構(gòu)體。
-
三種驗(yàn)證模式
無(wú)條件信任服務(wù)器的證書
伙单、對(duì)公鑰驗(yàn)證
获高、對(duì)證書驗(yàn)證
的具體邏輯。后兩種需要我們本地自建證書(由服務(wù)器提供原始證書生成)吻育。
如果不需要驗(yàn)證什么念秧、壓根不需要設(shè)置AFSecurityPolicy
、因?yàn)樵趍anager的初始化里已經(jīng)默認(rèn)了一個(gè)AFSecurityPolicy
并且被設(shè)置成無(wú)條件信任服務(wù)器的證書
布疼。當(dāng)然摊趾、這樣你的HTTPS除了加密通道意外將毫無(wú)用處、而這個(gè)通道游两、也是可以被抓包的砾层。
其實(shí)整個(gè)模塊也沒(méi)有太多可以研究的地方、因?yàn)槎际枪潭ǖ姆椒浮D阒荒苓@么寫~
不過(guò)肛炮、一行一行看一看。iOS的證書到底是如何驗(yàn)證的宝踪、也不錯(cuò)侨糟。
有興趣可以參閱《iOS源碼補(bǔ)完計(jì)劃--AFNetworking(三)》
知識(shí)點(diǎn)
-
__Require_Quiet判斷
宏__Require_Quiet
和__Require_noErr_Quiet
作用其實(shí)和if-esle
差不多、但是可以從多個(gè)入口跳到統(tǒng)一的出口瘩燥、相關(guān)函數(shù)__Require_XXX
基本都是這個(gè)意思秕重。寫了幾個(gè)小方法、想看的自己可以copy運(yùn)行一下
#import <AssertMacros.h>
//斷言為假則會(huì)執(zhí)行一下第三個(gè)action厉膀、拋出異常溶耘、并且跳到_out
__Require_Action(1, _out, NSLog(@"直接跳"));
//斷言為真則往下二拐、否則跳到_out
__Require_Quiet(1,_out);
NSLog(@"111");
//如果不注釋、從這里直接就會(huì)跳到out
// __Require_Quiet(0,_out);
// NSLog(@"222");
//如果沒(méi)有錯(cuò)誤汰具、也就是NO卓鹿、繼續(xù)執(zhí)行
__Require_noErr(NO, _out);
NSLog(@"333");
//如果有錯(cuò)誤、也就是YES留荔、跳到_out吟孙、并且拋出異常定位
__Require_noErr(YES, _out);
NSLog(@"444");
_out:
NSLog(@"end");
2018-05-17 14:18:12.656703+0800 AFNetWorkingDemo[4046:313255] 111
2018-05-17 14:18:12.656944+0800 AFNetWorkingDemo[4046:313255] 333
AssertMacros: YES == 0 , file: /Users/kiritoSong/Desktop/博客/KTAFNetWorkingDemo/AFNetWorkingDemo/AFNetWorkingDemo/ViewController.m, line: 39, value: 1
2018-05-17 14:18:12.657097+0800 AFNetWorkingDemo[4046:313255] end
這樣、我們就有了三種判斷的方式
1聚蝶、普通邏輯的if-else
2杰妓、編譯級(jí)別的#if - #esle - #endif
3、__Require_XXX這種多入口碘勉、統(tǒng)一出口的宏判斷
AFHTTPRequestSerializer
負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求NSMutableURLRequest對(duì)象的初始化
以及請(qǐng)求頭巷挥、請(qǐng)求體、參數(shù)验靡、上傳文件的自動(dòng)化配置
幾千行代碼倍宾、很長(zhǎng)。但是讀下來(lái)會(huì)受益匪淺胜嗓。
-
流程圖
流程看起來(lái)很簡(jiǎn)單高职、但是具體實(shí)施起來(lái)卻有很多東西。
包括如何將參數(shù)字典轉(zhuǎn)化成字符串并且轉(zhuǎn)譯辞州、如何進(jìn)行文件的分段拼接拷貝怔锌、如何將一個(gè)個(gè)請(qǐng)求體文件整合到request中等等。
詳細(xì)的API可以參閱:《iOS源碼補(bǔ)完計(jì)劃--AFNetworking(四)》
AFHTTPResponseSerializer
主要看了看AFURLResponseSerialization的內(nèi)容
負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求成功之后服務(wù)器返回的響應(yīng)體進(jìn)行格式化
核心代碼
AFURLResponseSerialization
協(xié)議以及其解碼方法
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
data:(nullable NSData *)data
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
針對(duì)不同的解析器(JSON/XML/PList等)变过、通過(guò)實(shí)現(xiàn)這個(gè)協(xié)議的方式埃元。
在請(qǐng)求結(jié)束時(shí)、幫助AFURLSessionManager
對(duì)獲得的響應(yīng)體進(jìn)行解析媚狰。
詳細(xì)的API可以移步:《iOS源碼補(bǔ)完計(jì)劃--AFNetworking(五)》
知識(shí)點(diǎn)
-
協(xié)議的應(yīng)用
- 通過(guò)讓多個(gè)對(duì)象遵循同一份協(xié)議的方式岛杀、可以在解耦的時(shí)候代替繼承、然后重載父類方法時(shí)通用做法哈雏。使得一個(gè)協(xié)議楞件、返回不同的結(jié)果。
- 在多人協(xié)作的時(shí)候裳瘪、約定好協(xié)議然后交由其他業(yè)務(wù)實(shí)現(xiàn)、也是提升開(kāi)發(fā)效率很普遍的方式罪针。
-
如何在一個(gè)方法中返回兩個(gè)NSError
可以使用嵌套的方式彭羹、比如NSUnderlyingErrorKey
來(lái)指定一個(gè)最主要的錯(cuò)誤。
-
NSIndexSet對(duì)象
NSIndexSet這個(gè)合集泪酱、是NSSet的數(shù)字版派殷。
一個(gè)無(wú)符號(hào)整數(shù)的集合还最、內(nèi)部元素具有唯一性。
NSMutableIndexSet *indexSetM = [NSMutableIndexSet indexSet];
[indexSetM addIndex:19];
[indexSetM addIndex:4];
[indexSetM addIndex:6];
[indexSetM addIndex:8];
[indexSetM addIndexesInRange:NSMakeRange(20, 10)];
[indexSetM enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%lu",idx);
}];
//2016-08-10 11:39:00.826 qikeyunDemo[3765:100078] 4
//2016-08-10 11:39:00.827 qikeyunDemo[3765:100078] 6
//2016-08-10 11:39:00.827 qikeyunDemo[3765:100078] 8
//2016-08-10 11:39:00.827 qikeyunDemo[3765:100078] 19
//2016-08-10 11:39:00.827 qikeyunDemo[3765:100078] 20
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 21
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 22
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 23
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 24
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 25
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 26
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 27
//2016-08-10 11:39:00.828 qikeyunDemo[3765:100078] 28
//2016-08-10 11:39:00.829 qikeyunDemo[3765:100078] 29
內(nèi)部元素會(huì)自動(dòng)排序
-
服務(wù)器返回的圖片是壓縮過(guò)的
服務(wù)器返回的圖片毡惜、需要被解壓出bitmap信息拓轻。
bitmap的作用在于在將UIImage交付給UIImageView的時(shí)候。
如果沒(méi)有bitmap將會(huì)在主線程自動(dòng)解壓一次经伙。
最后
本文主要是自己的學(xué)習(xí)與總結(jié)扶叉。如果文內(nèi)存在紕漏、萬(wàn)望留言斧正帕膜。如果不吝賜教小弟更加感謝枣氧。
參考資料
AFNetworking到底做了什么?(終)
iOS源碼補(bǔ)完計(jì)劃--AFNetworking(一)
iOS源碼補(bǔ)完計(jì)劃--AFNetworking(二)
iOS源碼補(bǔ)完計(jì)劃--AFNetworking(三)
iOS源碼補(bǔ)完計(jì)劃--AFNetworking(四)
iOS源碼補(bǔ)完計(jì)劃--AFNetworking(五)
馬在路上----一個(gè)寫了很多源碼解讀的大神