AFNetworking框架是一個使用很是普遍的框架,如今幾乎已經佔據了iOS開發中網絡層的主導地位,成爲行業標準。究其緣由,其代碼自己的質量很是高,設計很是優秀,使用也很是方便。
咱們平時在網上看到的大可能是如何來使用AFNetworking的文章,少有剖析實現原理。雖然咱們沒有必要再造一個輪子,可是理解輪子如何製造有助於提升咱們自身的能力,也能夠避免在使用過程當中踩坑。
這個系列的文章是鄙人學習AF框架過程當中所做的筆記,分享出來以供你們觀摩批評,若有理解不到位的地方,歡迎你們批評指正。編程
AFNetworkReachabilityManager是af庫中用於臨測網絡狀態,網絡狀態變化的工具。使用這個工具能夠獲得當前系統是否可接入網絡,使用什麼方式接入網絡(Wifi or WWAN?),以及在網絡發生變化時獲得相應的通知。網絡
manager對象的networkReachabilityStatus 屬性標記當前的網絡狀態,有如下幾種選項
AFNetworkReachabilityStatusUnknown 未知的網絡狀態
AFNetworkReachabilityStatusNotReachable 當前處於一個無網的狀態,或者被禁用的網絡狀態
AFNetworkReachabilityStatusReachableViaWWAN 當前網絡使用移動
AFNetworkReachabilityStatusReachableViaWiFi 當前使用wifi鏈接網絡框架
可使用提供的單例,也能夠本身建立一個新的實例來檢查網絡異步
[[AFNetworkReachabilityManager sharedManager] startMonitoring]; [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSString *statusstr = AFStringFromNetworkReachabilityStatus(status); NSLog(@"network : %@", statusstr); }];
注意,若是啓動時就去獲取,這時得到的狀態可能會爲Unknownasync
[[AFNetworkReachabilityManager sharedManager] startMonitoring]; NSString *statusstr = AFStringFromNetworkReachabilityStatus(status); // statusstr = @"unknown...";
這裏列舉中間所用到的不常見的知識點,諸如單例、靜態函數等不在此列函數
SCNetworkReachabilityRef 是SystemConfiguration framework中的一個類,專門用於檢測和關注網絡狀態,使用C語言風格進行編程。
主要的函數有如下幾個:SCNetworkRechabilityRef SCNetworkReachabilityCreateWithAddress(CFAllocatorRef allocator, const struct sockaddr *address)
建立該對象的引用,第一個參數可使用NULL或者kCFAllocatorDefault,第二個參數爲目標地址,若是傳入0.0.0.0則用於查詢本機網絡狀態。
在咱們的AFReachabilityManager中,+manager方法使用了這個函數來建立一個默認的,用於0.0.0.0的鏈接器。工具
struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_len = sizeof(address); address.sin_family = AF_INET; [self managerForAddress:&address];
Boolean SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags)
用於獲取網絡的鏈接狀態值,若是獲取成功,返回TRUE。oop
Boolean SCNetworkReachabilityScheduleWithRunLoop ( SCNetworkReachabilityRef target, CFRunLoopRef runLoop, CFStringRef runLoopMode ) Boolean SCNetworkReachabilityUnscheduleFromRunLoop ( SCNetworkReachabilityRef target, CFRunLoopRef runLoop, CFStringRef runLoopMode ) Boolean SCNetworkReachabilitySetCallback ( SCNetworkReachabilityRef target, SCNetworkReachabilityCallBack __nullable callout, SCNetworkReachabilityContext * __nullable context )
這三個函數用於將screachability對象加入到runloop中,在網絡狀態發生變化時觸發回調得到相應的通知。
要使用這三個方法,首先必須先配置好回調函數學習
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info); }
而後使用 SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
函數將callback添加到screachability中。
注意這裏還有一個context參數 SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
callback是一個已定義好的block對象,而retainCallback和releaseCallback則決定了以後如何對這個callback對象進行引用。
這個callback將在隨後的回調觸發中,被傳入到AFNetworkReachabilityCallback函數中被使用。spa
KVO機制咱們在平時的開發中也常常會有使用,不過比較深刻和偏門一些的知識點則不是那麼的常見了,在AFReachabilityManager中使用到了一個方法
+(NSSet )keyPathsForValuesAffectingValueForKey:(NSString )key,這個方法決定了哪些key值會影響到其餘的key值的observing。
好比
+(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { return [NSSet setWithObject:@"networkReachabilityStatus"]; } return [super keyPathsForValuesAffectingValueForKey:key]; }
這個方法指明,若是networkReachabilityStatus屬性被改變,那麼reachable、reachableViaWWAN、reachableViaWiFi這幾個屬性的觀察者也會收到通知。
這個流程圖標識了AFReachability使用SCNetworkReachability併產生回調的過程
經過上面的流程圖,你們能夠看到,AFReachability對象建立之後並不會當即去取status,而是在startMonitor方法之後,纔會去取得SC中的status,
即便如此,源代碼中也是使用異步的方法去取的SCReachability的status,因此咱們在使用startMonitor方法以後,並不能穩定的取得當前的網絡狀態,而是必需在回調中才能獲得。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } });