AFNetworking 全解析之RechabilityManager

一个关于AFNetworking的系列

AFNetworking框架是一个使用非常广泛的框架,现在几乎已经占据了iOS开发中网络层的主导地位,成为行业标准。究其原因,其代码本身的质量非常高,设计非常优秀,使用也非常方便。
我们平时在网上看到的大多是如何来使用AFNetworking的文章,少有剖析实现原理。虽然我们没有必要再造一个轮子,但是理解轮子如何制造有助于提高我们自身的能力,也可以避免在使用过程中踩坑。
这个系列的文章是鄙人学习AF框架过程中所作的笔记,分享出来以供大家观摩批评,如有理解不到位的地方,欢迎大家批评指正。

AFNetworkReachabilityManager的作用

AFNetworkReachabilityManager是af库中用于临测网络状态,网络状态变化的工具。使用这个工具可以得到当前系统是否可接入网络,使用什么方式接入网络(Wifi or WWAN?),以及在网络发生变化时得到相应的通知。

定义的几种网络状态

manager对象的networkReachabilityStatus 属性标记当前的网络状态,有以下几种选项
AFNetworkReachabilityStatusUnknown 未知的网络状态
AFNetworkReachabilityStatusNotReachable 当前处于一个无网的状态,或者被禁用的网络状态
AFNetworkReachabilityStatusReachableViaWWAN 当前网络使用移动
AFNetworkReachabilityStatusReachableViaWiFi 当前使用wifi连接网络

使用AF查看当前网络状态

可以使用提供的单例,也可以自己创建一个新的实例来检查网络

[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    NSString *statusstr = AFStringFromNetworkReachabilityStatus(status);
    NSLog(@"network : %@", statusstr);
}];

注意,如果启动时就去获取,这时获得的状态可能会为Unknown

[[AFNetworkReachabilityManager sharedManager] startMonitoring];
NSString *statusstr = AFStringFromNetworkReachabilityStatus(status);
// statusstr = @"unknown...";

RechabilityManager类中所涉及的知识点

这里列举中间所用到的不常见的知识点,诸如单例、静态函数等不在此列

SCNetworkReachabilityRef

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。

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函数中被使用。

KeyValueAffecting

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这几个属性的观察者也会收到通知。

UML结构图

AFNetworking 全解析之RechabilityManager

调用流程图

这个流程图标识了AFReachability使用SCNetworkReachability并产生回调的过程
AFNetworking 全解析之RechabilityManager

AFReachability的缺点

通过上面的流程图,大家可以看到,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);
        }
    });

相关推荐