前言
- 闲的蛋疼
- 分析下AFNetworkReachabilityManager源码
一、
- 1.AFNetworkReachabilityManager是AFNetworking 的一个监控网络状态的类,用来帮助我们监听网络的变化
- 2.先说结论,AFNetworkReachabilityManager调用了原生的SCNetworkReachabilityRef
- 3.SCNetworkReachabilityRef 来自 SystemConfiguration.framework , 其中工具 SCNetworkReachability 就是用来监测网络状况的
https://github.com/yaotao1995/YTAFNetworkingInterpretation.git
二、简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) { case AFNetworkReachabilityStatusReachableViaWiFi: break;
case AFNetworkReachabilityStatusNotReachable: break; case AFNetworkReachabilityStatusUnknown: break;
case AFNetworkReachabilityStatusReachableViaWWAN: break; default: break; } }];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
|
二、源码
- 不上代码都是耍流氓,下面是AFNetworkReachabilityManager的初始化方法
1.单例模式维护了一个AFNetworkReachabilityManager,单例中最终调用了manager来初始化
1 2 3 4 5 6 7 8
| +(instancetype)sharedManager { static AFNetworkReachabilityManager *_sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedManager = [self manager]; }); return _sharedManager; }
|
2.来看看函数 manager ,先简单看下,条件成立与否都返回address 这个结构体 给函数managerForAddress,区别就在于条件成立 结构体类型是sockaddr_in6 ,不成立使用 sockaddr_in,以及结构体成员变量sin_family的赋值问题;至于bzero()内存分配方法暂且先不管;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| + (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]; }
|
3.先看下条件,其中两部分条件可以分为:MAC_OS的版本要求以及IPHONE_OS版本要求,这里暂且就看下IPHONE_OS 的版本要求,要求__IPHONE_OS_VERSION_MIN_REQUIRED 值大于等于 90000 即 版本大于等于ios9
1 2
| (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)
|
4.两结构体看原文注释就知道了 sockaddr_in6:Socket address for IPv6;sockaddr_in:Socket address, internet style.也就是说
在这里区分了ipv6 和 ipv4 的,这里存在一个ipv4和ipv6的转换问题有兴趣可以查资料看下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct sockaddr_in6 { __uint8_t sin6_len; sa_family_t sin6_family; in_port_t sin6_port; __uint32_t sin6_flowinfo; struct in6_addr sin6_addr; __uint32_t sin6_scope_id; }; struct sockaddr_in { __uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; };
|
5.再往下走 得到区分ipv6的地址之后 managerForAddress:(const void *)address 函数
这里我们可以较为清楚看到,af实际调用的就是 原生的 SCNetworkReachabilityRef
使用这个SCNetworkReachabilityRef创建了我们的AFNetworkReachabilityManager
查看 SCNetworkReachabilityRef,它也是个结构体,官方解释为:网络地址或名字的句柄
1 2 3 4 5 6
| + (instancetype)managerForAddress:(const void *)address { SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; CFRelease(reachability); return manager; }
|
6.这里我贴一段使用 SystemConfiguration.framework 反汇编出来的 SCNetworkReachabilityCreateWithAddress函数的伪代码 有兴趣可以看下
1 2 3 4 5 6 7
| int _SCNetworkReachabilityCreateWithAddress(int arg0, int arg1) { r7 = (sp - 0x14) + 0xc; sp = sp - 0x24; r4 = arg0; var_1C = *0x3e5e5944; r5 = _is_valid_address(arg1); if (r5 == 0x0) goto loc_1b2278be;
|
7.到这里AFNetworkReachabilityManager还没创建好,CFRetain表示传入的reachability不为空,赋给本身的SCNetworkReachabilityRef,并且修改状态为 AFNetworkReachabilityStatusUnknown,至此初始化完成
1 2 3 4 5 6 7 8 9
| - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability { self = [super init]; if (!self) { return nil; } _networkReachability = CFRetain(reachability); self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; return self; }
|
三、使用
8.创建好了,接下去要用了,startMonitoring函数是开启监测用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| - (void)startMonitoring { //启用之前先调用停止函数 [self stopMonitoring]; //判断上述的SCNetworkReachabilityRef是否存在 if (!self.networkReachability) { return; }
//写好block,用来回调状态 __weak __typeof(self)weakSelf = self; AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { __strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } };
//SCNetworkReachabilityContext 这个结构体保存了用户的数据,以及SCNetworkReachabilitySetCallback回调的信息 SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
//只有SCNetworkReachabilitySetCallback设置了 上述SCNetworkReachabilityContext 结构体 ,才能生效 SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
//SCNetworkReachabilityScheduleWithRunLoop 接收三个参数,创建的self.networkReachability,需要循环在哪个runloop上,以及runloop的模式,当网络状态发生变化时就会执行SCNetworkReachabilitySetCallback方法中的callout回调 //也就是说,这里将创建的self.networkReachability 丢进去,在主线程上循环,runloop模式为 kCFRunLoopCommonModes SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); // 异步 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ //SCNetworkReachabilityFlags 状态标识 就是这个了,我们最终要得到的状态标识就是这个flags!!!!!!! SCNetworkReachabilityFlags flags; //SCNetworkReachabilityGetFlags 获取网络状态丢到 flags ,最后将网络状态callback if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { AFPostReachabilityStatusChange(flags, callback); } }); }
|
四、其他
- 这段时间在复习汇编,等汇编复习完了,再从汇编的角度分析下…