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); } });