趁着端午節日,本身沒有什麼過多的安排,準備花4-5天左右,針對網絡請求源碼AFNetworking和YTKNetwork進行解析以及這兩年多iOS實際開發經驗(其實YTKNetwork也是對AFNetworking的深度封裝),結合多個實際項目,分別針對這兩個網絡框架,進行封裝使用(能夠直接使用)。本篇主要講解AFNetworking源碼解析,都是本身親自看AFNetworking源碼以及心得體會,大約看下來須要20-30分鐘。歡迎指正!!!html
AFNetworking源碼地址:https://github.com/AFNetworking/AFNetworkinggit
針對AFNetworking封裝:http://www.javashuo.com/article/p-tpkndbbq-v.htmlgithub
YTKNetwork的源碼詳解:http://www.javashuo.com/article/p-spkgoewu-bv.html緩存
一.AFNetworking的代碼結構:安全
新的代碼結構將AFNetworking.h放到了Supporting Files裏面。服務器
自從AFNetworking結構更改之後,結構可能不夠清晰,之前的版本是這樣的:網絡
其實沒有多少改變,從這張圖能夠看出:除去Support Files,能夠看到AF分爲以下5個功能模塊:session
二.各種講解app
1.網絡通訊模塊-AFURLSessionManager與AFHTTPSessionManager框架
AFHTTPSessionManager是繼承AFURLSessionManager的,至關於對AFURLSessionManager的再次封裝。
(1)AFURLSessionManager
1>經過查看AFURLSessionManager類:
發現AFURLSessionManager遵照NSSecureCoding, NSCopying兩個協議,以及遵照
NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate四個代理。在AFURLSessionManager中實現協議裏的方法,用來處理網絡請求中不一樣的狀況:例如:暫停,取消,數據保存,更新數據進度條同樣。
2>下面是查看AFURLSessionManager類,所包含的屬性:
3>下面是AFURLSessionManager的方法
(1)
若是入參configuration爲nil,則調用NSURLSessionConfiguration的defaultSessionConfiguration方法,建立一個會話配置,並使用該配置建立一個會話對象,同時還初始化了安全策略、鎖、返回數據解析器(JSON 數據解析器)等屬性。
(2)
此方法是取消會話Session,發現cancelPendingTasks是一個BOOL類型,若是返回NO,意思是容許會話中的任務執行完畢後,再取消會話,可是會話一經取消將沒法重啓;反之若是返回YES,那麼直接取消會話,其相關聯的任務和回調都將會釋放。
(3)
再看一下實現方法:
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler]; } - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler { __block NSURLSessionDataTask *dataTask = nil; url_session_manager_create_task_safely(^{ dataTask = [self.session dataTaskWithRequest:request]; }); [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler]; return dataTask; }
建立數據服務,這裏在使用會話對象 session 和入參 request 建立任務時,若是 NSFoundationVersionNumber 的值小於 NSFoundationVersionNumber_iOS_8_0
那麼 dataTask 的建立會放在 af_url_session_manager_creation_queue
串行隊列中同步執行,不然就由當前線程執行。接着,會調用這樣的方法:
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler{ AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask]; delegate.manager = self; delegate.completionHandler = completionHandler; dataTask.taskDescription = self.taskDescriptionForSessionTasks; [self setDelegate:delegate forTask:dataTask]; delegate.uploadProgressBlock = uploadProgressBlock; delegate.downloadProgressBlock = downloadProgressBlock; }
在這個方法中會建立一個AFURLSessionManagerTaskDelegate對象,設置其相關聯的管理器,任務描述以及回調等甦醒,還會將當前會話註冊爲監聽者,監聽 task 任務發出的 AFNSURLSessionTaskDidResumeNotification 和 AFNSURLSessionTaskDidSuspendNotification 通知。當接收到該通知後,分別執行 taskDidResume: 和 taskDidSuspend: 方法,在這兩個方法中又發出了 AFNetworkingTaskDidResumeNotification 和 AFNetworkingTaskDidSuspendNotification 通知。
(4)
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler]; }
建立數據服務,這個方法實際上是調用了上一個方法,只是uploadProgress和downloadProgress傳nil而已
(5)
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; }); if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) { uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; } } [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; return uploadTask; }
此方法是建立文件上傳任務,若是果後臺會話對象建立文件上傳任務失敗時,會根據條件嘗試從新建立,固然 AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask 爲 5 ,因此只能嘗試 5次。若是任務建立成功,則進而爲任務建立一個 AFURLSessionManagerTaskDelegate 對象,做爲任務的代理。請求報文的請求體數據即爲根據參數 fileURL 獲取的文件數據。
(6)
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler { __block NSURLSessionUploadTask *uploadTask = nil; url_session_manager_create_task_safely(^{ uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData]; }); [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; return uploadTask; }
此方法上傳數據與上面上傳文件相似,待上傳的數據直接由參數 bodyData 給出。
(7)
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler { __block NSURLSessionDownloadTask *downloadTask = nil; url_session_manager_create_task_safely(^{ downloadTask = [self.session downloadTaskWithRequest:request]; }); [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler]; return downloadTask; }
建立下載任務:
進一步調用下面方法
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler { AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask]; delegate.manager = self; delegate.completionHandler = completionHandler; if (destination) { delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) { return destination(location, task.response); }; } downloadTask.taskDescription = self.taskDescriptionForSessionTasks; [self setDelegate:delegate forTask:downloadTask]; delegate.downloadProgressBlock = downloadProgressBlock; }
(8)
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData progress:(NSProgress * __autoreleasing *)progress destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler { __block NSURLSessionDownloadTask *downloadTask = nil; dispatch_sync(url_session_manager_creation_queue(), ^{ downloadTask = [self.session downloadTaskWithResumeData:resumeData]; }); [self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler]; return downloadTask; }
建立重用數據的下載任務:使用已經下載的部分數據 resumeData 建立一個下載任務,繼續進行下載。
(9)
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
獲取任務的數據上傳進度
(10)
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
獲取任務的數據下載進度
AFURLSessionManager 中實現的代理方法
AFURLSessionManager 遵循 NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate 協議,以處理網絡請求過程當中的數據。
有些代理方法中所作的任務,徹底由 AFURLSessionManager 的代碼塊屬性決定。若是這些屬性並無設置,那麼相應的代理方法就不必響應。因此 AFURLSessionManager 中重寫了 respondsToSelector: 過濾了一些沒必要響應的代理方法。
當下載任務結束後,調用該代理方法。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { //獲取與任務相對應的代理對象 AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; //若是設置了回調任務,先執行回調任務 if (self.downloadTaskDidFinishDownloading) { //獲取下載數據要保存的地址 NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); if (fileURL) { delegate.downloadFileURL = fileURL; NSError *error = nil; //移動下載的數據到指定地址 if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) { [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo]; } return; } } if (delegate) { [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; } }
從上面的代碼可知,若是會話管理器的 downloadTaskDidFinishDownloading 的代碼塊返回了地址,那麼便不會去執行任務自己所對應的代理方法了,而且若是移動文件失敗便會推送一個 AFURLSessionDownloadTaskDidFailToMoveFileNotification 通知。
下面兩個協議方法中,都是先執行任務所關聯的代理對象的方法,再執行會話對象設置的 downloadTaskDidWriteData 或 downloadTaskDidResume 任務。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes;
從這些代理方法中可知,設置 AFURLSessionManager 會話實例對象的代碼塊任務屬性,那麼這些回調任務對於每個網絡請求任務都是有效的,因此針對於單個特殊的任務回調操做,便不能放在會話管理器的屬性中,而是要放在與任務相關聯的 AFURLSessionManagerTaskDelegate 代理對象中。
實際使用 AFURLSessionManager 的方法建立網絡請求任務時,傳遞的回調任務,都是在與任務相關聯的代理對象的方法中執行的。
以上就是AFURLSessionManager的內容。下面講解他的子類:AFHTTPSessionManager
2>AFHTTPSessionManager
發現AFHTTPSessionManager是繼承AFURLSessionManager並遵照<NSSecureCoding, NSCopying>
(1)
/** The URL used to construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods. */ @property (readonly, nonatomic, strong, nullable) NSURL *baseURL; /** Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies. @warning `requestSerializer` must not be `nil`. */ @property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer; /** Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`. @warning `responseSerializer` must not be `nil`. */ @property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer; /** The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified. A security policy configured with `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate` can only be applied on a session manager initialized with a secure base URL (i.e. https). Applying a security policy with pinning enabled on an insecure session manager throws an `Invalid Security Policy` exception. */ @property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
暴露出的 baseUrl 屬性是 readonly
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 請求序列化
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 響應序列化
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
以及
+ (instancetype)manager;
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
三個初始化方法,第一個是類方法,後兩個是須要傳參的實例方法。
(2)請求方式
GET 請求是向服務端發起請求數據,用來獲取或查詢資源信息
POST 請求是向服務端發送數據的,用來更新資源信息,它能夠改變數據的種類等資源
PUT 請求和POST請求很像,都是發送數據的,可是PUT請求不能改變數據的種類等資源,它只能修改內容
DELETE 請求就是用來刪除某個資源的
PATCH 請求和PUT請求同樣,也是用來進行數據更新的,它是HTTP verb推薦用於更新的
在實際開發過程當中,咱們仍是使用【GET 和 POST】請求是最多的。
其實若是看一下AFHTTPSessionManager,發現裏面並無須要講什麼的,關鍵仍是AFURLSessionManager類。
下面以GET請求爲例:
//GET請求,調用下面那個方法 - (NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure { return [self GET:URLString parameters:parameters progress:nil success:success failure:failure]; } //GET請求 - (NSURLSessionDataTask *)GET:(NSString *)URLString parameters:(id)parameters progress:(void (^)(NSProgress * _Nonnull))downloadProgress success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure { //調用另外一個方法構造GET請求 NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:downloadProgress success:success failure:failure]; /* 啓動任務 使用AFHTTPSessionManager建立的任務默認都幫你啓動了,因此不須要手動調用resume方法了 上一篇中講解的AFURLSessionManager默認沒有啓動,因此獲取任務後要手動啓動 */ [dataTask resume]; return dataTask; }
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress success:(void (^)(NSURLSessionDataTask *, id))success failure:(void (^)(NSURLSessionDataTask *, NSError *))failure { NSError *serializationError = nil; NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; if (serializationError) { if (failure) { dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ failure(nil, serializationError); }); } return nil; } __block NSURLSessionDataTask *dataTask = nil; //利用AFURLSessionManager方法 dataTask = [self dataTaskWithRequest:request uploadProgress:uploadProgress downloadProgress:downloadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { if (error) { if (failure) { failure(dataTask, error); } } else { if (success) { success(dataTask, responseObject); } } }]; return dataTask; }
2.AFNetworkReachabilityManager
AFNetworkReachabilityManager對象用於監聽設備當前鏈接網絡的狀態。
AFNetworkReachabilityManager提供了4種建立方法:
/** Returns the shared network reachability manager. */ + (instancetype)sharedManager; /** Creates and returns a network reachability manager with the default socket address. @return An initialized network reachability manager, actively monitoring the default socket address. */ + (instancetype)manager; /** Creates and returns a network reachability manager for the specified domain. @param domain The domain used to evaluate network reachability. @return An initialized network reachability manager, actively monitoring the specified domain. */ + (instancetype)managerForDomain:(NSString *)domain; /** Creates and returns a network reachability manager for the socket address. @param address The socket address (`sockaddr_in6`) used to evaluate network reachability. @return An initialized network reachability manager, actively monitoring the specified socket address. */ + (instancetype)managerForAddress:(const void *)address;
+ (instancetype)shareManager{ static AFNetworkReachabilityManager *_shareManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ _shareManager = [self manager]; ) ; return _shareManager; }
sharedManager調用manager方法建立一個AFNetworkReachabilityManager對象,代碼以下:
//其中sockaddr_in6和sockaddr_in是描述網絡套接字的結構體,包含協議族類型、端口、ip地址等信息,而後調用managerForAddress:方法建立, + (instancetype)manager { #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) struct sockaddr_in6 address; bzero(&address, sizeof(address)); address.sin6_len = sizeof(address); address.sin6_family = AF_INET6; #else struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_len = sizeof(address); address.sin_family = AF_INET; #endif return [self managerForAddress:&address]; }
其餘的兩種方法: 一個根據地址名建立實例對象,另外一個根據sockaddr建立實例對象,能夠直接看源代碼,用的並非特別多。
(2)經過枚舉值查看網絡狀態
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { AFNetworkReachabilityStatusUnknown = -1,//未知狀態 AFNetworkReachabilityStatusNotReachable = 0, //未鏈接 AFNetworkReachabilityStatusReachableViaWWAN = 1, //蜂窩移動網絡(2G/3G/4G) AFNetworkReachabilityStatusReachableViaWiFi = 2, //wifi網絡 };
(3)網絡監聽
AFNetworkReachabilityManager經過startMonitoring方法和stopMonitoring開始並中止監聽當前設備鏈接的網絡狀態。
1>startMonitoring方法
該方法主要經過SystemConfiguration框架提供的API將networkReachability讓對象加入runloop中,開始工做,而且綁定監聽的回調函數處理狀態改變。
- (void)startMonitoring { [self stopMonitoring]; if (!self.networkReachability) { return; } __weak __typeof(self)weakSelf = self; AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf; strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } }; SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } }); }
根據查看源碼發現:該方法首先中止以前的監聽,而後調用SCNetworkReachabilitySetCallback方法來設置networkReachability的回調函數AFNetworkReachabilityCallback和上下文context對象。
在回調方法中有一個方法比較重要:
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) { AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); //根據flags獲取當前網絡鏈接狀態status dispatch_async(dispatch_get_main_queue(), ^{ if (block) { block(status); //block是context中的info指針,調用info將status傳遞給外界 } //status做爲通知的值,發通知拋給外界 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) }; [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo]; }); }
此方法首先根據系統回調的AFNetworkReachabilityStatusForFlags方法以及falgs參數,獲取網絡鏈接狀態,而後進入block,將status拋出外界,同時拋一個通知將status拋給外界,當網絡狀態發生改變,會同事用這兩種方式傳遞給外界。
AFNetworkReachabilityStatusForFlags方法是核心方法,負責根據flag的狀態值,轉化爲相應的枚舉值AFNetworkReachabilityStatus。
2>stopMonitoring方法
該方法經過監聽的方法是讓networkReachability對象從runloop中註銷。
- (void)stopMonitoring { if (!self.networkReachability) { return; } SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); }
(3)網絡屬性狀態
/** The current network reachability status. */ @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; /** Whether or not the network is currently reachable. */ @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable; /** Whether or not the network is currently reachable via WWAN. */ @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN; /** Whether or not the network is currently reachable via WiFi. */ @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
經過上面可發現:外界可經過isReachable方法,isReachableViaWWAN方法以及isReachableViaWiFi等獲取當前的網絡狀態。經過keyPathsForValuesAffectingValueForKey方法設置屬性值的依賴關係,利用KVO方式監聽屬性的變化。
下面是簡單的一個網絡監聽的小demo
1)[[AFNetworkReachabilityManagersharedManager] startMonitoring];
2)判斷網絡鏈接狀態。
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { switch (status) { case AFNetworkReachabilityStatusNotReachable:{ NSLog(@"無網絡"); break; } case AFNetworkReachabilityStatusReachableViaWiFi:{ NSLog(@"WiFi網絡"); break; } case AFNetworkReachabilityStatusReachableViaWWAN:{ NSLog(@"3G網絡"); break; } default: break; } }];
3.AFSecurityPolicy
首先看一下AFSecurityPolicy暴露出來的方法。
//https驗證模式 默認是無,還有證書匹配和公鑰匹配 @property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode; //能夠去匹配服務端證書驗證的證書 當咱們不主動設置pinningMode的時候不會主動該字段是空的,若是主動設置,會調用默認讀取certificatesInBundle .cer的證書進行賦值 源碼裏面有 @property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates; //allowInvalidCertificates 是否容許無效證書(也就是自建的證書),默認爲NO //若是是須要驗證自建證書,須要設置爲YES 通常測試的時候YES,https開啓就弄爲NO @property (nonatomic, assign) BOOL allowInvalidCertificates; //validatesDomainName 是否須要驗證域名,默認爲YES; //假如證書的域名與你請求的域名不一致,需把該項設置爲NO;如設成NO的話,即服務器使用其餘可信任機構頒發的證書,也能夠創建鏈接,這個很是危險,建議打開。 //置爲NO,主要用於這種狀況:客戶端請求的是子域名,而證書上的是另一個域名。由於SSL證書上的域名是獨立的,假如證書上註冊的域名是www.google.com,那麼mail.google.com是沒法驗證經過的;固然,有錢能夠註冊通配符的域名*.google.com,但這個仍是比較貴的。 //如置爲NO,建議本身添加對應域名的校驗邏輯。 @property (nonatomic, assign) BOOL validatesDomainName;
AFNetworking認證核心代碼
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { //挑戰處理類型爲 默認 /* NSURLSessionAuthChallengePerformDefaultHandling:默認方式處理 NSURLSessionAuthChallengeUseCredential:使用指定的證書 NSURLSessionAuthChallengeCancelAuthenticationChallenge:取消挑戰 */ NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; // 服務器挑戰的證書 __block NSURLCredential *credential = nil; // 這個Block是提供給用戶自定義證書挑戰方式的,好比是否須要自定義 if (self.sessionDidReceiveAuthenticationChallenge) { disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential); } else { // NSURLAuthenticationMethodServerTrust 單向認證關係 也就是說服務器端須要客戶端返回一個根據認證挑戰的保護空間提供的信任產生的挑戰證書 if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { // 基於客戶端的安全策略來決定是否信任該服務器,不信任的話,也就不必響應挑戰 if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { // 建立挑戰證書(注:挑戰方式爲UseCredential和PerformDefaultHandling都須要新建挑戰證書) credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; if (credential) { disposition = NSURLSessionAuthChallengeUseCredential; } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } } // 完成挑戰 if (completionHandler) { completionHandler(disposition, credential); } }
4.AFURLRequestSerialization
AFURLRequestSerialization涉及兩個模塊:AFURLRequestSerialization和AFURLResponseSerialization
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;
協議中刪除圖片
- (BOOL)removeImageWithIdentifier:(NSString *)identifier;
協議中刪除全部圖片
- (BOOL)removeAllImages;
經過identifier獲取圖片的方法:
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;
(2)UIButton+AFNetworking
UIButton跟圖片相關的屬性大概有兩個,Image
和BackgroundImage
.因此這個分類就是賦予他們異步加載圖片的能力。
核心方法有如下:
- (void)setImageForState:(UIControlState)state withURL:(NSURL *)url; - (void)setImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(nullable UIImage *)placeholderImage; - (void)setImageForState:(UIControlState)state withURLRequest:(NSURLRequest *)urlRequest placeholderImage:(nullable UIImage *)placeholderImage success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure; - (void)setBackgroundImageForState:(UIControlState)state withURL:(NSURL *)url; - (void)setBackgroundImageForState:(UIControlState)state withURL:(NSURL *)url placeholderImage:(nullable UIImage *)placeholderImage; - (void)setBackgroundImageForState:(UIControlState)state withURLRequest:(NSURLRequest *)urlRequest placeholderImage:(nullable UIImage *)placeholderImage success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
(3)UIImageView+AFNetworking
UIImageView+AFNetworking 是AFNetworking中一個實現圖片異步加載的類, 它是爲系統中的UIImageView類添加的類目(Category), 這個類目中的方法爲遠程異步加載圖片功能提供支持.
思路:
實現異步加載:
/* 建立NSURL對象 */ NSURL *urlStr = [NSURL URLWithString:@"http://img2.cache.netease.com/3g/2015/9/18/20150918195439dc844.jpg"]; /* 建立請求對象 */ NSURLRequest *request = [NSURLRequest requestWithURL:urlStr]; /* 建立一個imageView對象 */ UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
方法一:
/** * 方法一: * 直接使用url字符串獲取照片 * @param urlStr : NSURL對象 */ [imageView setImageWithURL:urlStr];
方法二:
/** * 方法二: * 直接使用URL(例如:http://img2.cache.netease.com/3g/2015/9/18/20150918195439dc844.jpg)異步加載圖片, 照片出現以前添加一個佔位的背景照片 * @param urlStr : NSURL對象 * @param placeholderImage : UIImage圖片對象 */ [imageView setImageWithURL:urlStr placeholderImage:[UIImage imageNamed:@"discuss"]];
方法三:
/** * 方法三: * 使用URLRequest對象獲取照片, 照片在請求後的block塊中返回一個UIImage參數用於賦值或其餘做. * 參數中得兩個block塊:分別在請求成功時執行 success:^{}, 請求失敗時執行 failure:^{}。 * @param request : NSURLRequest請求對象 * @param placeholderImage : UIImage圖片對象 */ [imageView setImageWithURLRequest:request placeholderImage:[UIImage imageNamed:@"discuss"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { /** * 返回值參數 * @param request : NSURLRequest 請求對象 * @param response : NSHTTPURLResponse HTTP響應者對象(包含請求對象和圖片信息) * @param image : 加載成功圖片UIImage對象(自帶的size尺寸用於自適應高度計算) */ [imageView setImage:image]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { /**< @param error : NSError對象 加載錯誤的緣由代號(例如 : 403) */ }];
/** * 取消圖片請求操做 * 能夠直接取消本段代碼塊中在調用這個方法以前的全部異步加載操做(適當的地方慎重使用) */ [imageView cancelImageRequestOperation];
固然還有其餘一些的擴展協議,但使用並非不少,且看源碼不是很難。上面就是這兩天看AFNetworking源碼的一些本身感悟:由於AFNetworking主要是AFURLSessionManager、AFHTTPSessionManager,本身花7成都在上面,但願對你們對AFNetworking的理解有所加深,歡迎指正。
下一篇,我將結合本身的項目對AFNetworking的使用進行封裝,對中小型企業APP的網絡封裝能夠直接使用,謝謝你們!!!