AFNetworking3源码阅读-Reachability
用于监控网络状态。当网络状态改变时,是重新发起一些请求的好时间;网络状态的监控也能给用户更好的网络失败提示。
AFNetworkReachabilityManager
使用
1 2 3 4 5
| [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status)); }];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
|
结构
AFNetworkReachabilityManager中大概有这么几个方法:
初始化
sharedManager 使用GCD dispatch_once_t
单例化。具体实例调用 manager 方法。
+manager方法使用了这个函数来创建一个默认的,用于0.0.0.0的连接器
__IPHONE_OS_VERSION_MIN_REQUIRED
在iOS环境下(要求最低的系统版本);
__MAC_OS_X_VERSION_MIN_REQUIRED
则表示mac环境下要求的最低环境
90000 表示 __IPHONE_9_0
;101100 表示 __MAC_10_11
sockaddr_in6 代表ipv6地址
sockaddr_in 代表ipv4d地址
由于IPv6 是ios9和os_x 10.11后边推出的,这里要进行版本判断。
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]; }
|
通过SCNetworkReachabilityCreateWithAddress
生成SCNetworkReachabilityRef对象,通过监控该对象,即可获得网络连接情况。
1 2 3 4 5 6 7 8
| + (instancetype)managerForAddress:(const void *)address { SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; CFRelease(reachability); return manager; }
|
监听
开启监听后,获得连接状态会调用AFPostReachabilityStatusChange
,在AFPostReachabilityStatusChange中调用回调,并发送通知
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
| - (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); } }); }
|
关闭监听
1 2 3 4 5 6 7
| - (void)stopMonitoring { if (!self.networkReachability) { return; } SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); }
|
注册键值监听
重装keyPathsForValuesAffectingValueForKey,指明reachable 、reachableViaWWAN 和reachableViaWiFi属性依赖于networkReachabilityStatus。当networkReachabilityStatus改变时,观察reachable 、reachableViaWWAN 和reachableViaWiFi属性的程序需要被通知。
这是因为获得网络状态时,回调中只修改了networkReachabilityStatus值。
1 2 3 4 5 6 7
| + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { return [NSSet setWithObject:@"networkReachabilityStatus"]; }
return [super keyPathsForValuesAffectingValueForKey:key]; }
|
SCNetworkReachability
从上文可以看出监听主要使用的是SystemConfiguration框架中 SCNetworkReachability.h中的方法。这里介绍一下用到的方法和数据类型。
SCNetworkReachabilityFlags: 保存连接状态各个状态的含义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| typedef CF_OPTIONS(uint32_t, SCNetworkReachabilityFlags) { kSCNetworkReachabilityFlagsTransientConnection = 1<<0, kSCNetworkReachabilityFlagsReachable = 1<<1, kSCNetworkReachabilityFlagsConnectionRequired = 1<<2, kSCNetworkReachabilityFlagsConnectionOnTraffic = 1<<3, kSCNetworkReachabilityFlagsInterventionRequired = 1<<4, kSCNetworkReachabilityFlagsConnectionOnDemand = 1<<5, kSCNetworkReachabilityFlagsIsLocalAddress = 1<<16, kSCNetworkReachabilityFlagsIsDirect = 1<<17, #if TARGET_OS_IPHONE kSCNetworkReachabilityFlagsIsWWAN = 1<<18, #endif
kSCNetworkReachabilityFlagsConnectionAutomatic = kSCNetworkReachabilityFlagsConnectionOnTraffic };
|
SCNetworkReachabilityRef 用来测试连接的引用。有三种创建方式:
1 2 3
| SCNetworkReachabilityCreateWithAddress(allocator,address) SCNetworkReachabilityCreateWithAddressPair(allocator,localAddress,remoteAddress) SCNetworkReachabilityCreateWithName(allocator,nodename)
|
SCNetworkReachabilityContext 上下文是一个结构体:
1 2 3 4 5 6 7 8 9 10 11 12
| typedef struct { CFIndex version;
void * __nullable info;
const void * __nonnull (* __nullable retain)(const void *info);
void (* __nullable release)(const void *info);
CFStringRef __nonnull (* __nullable copyDescription)(const void *info); } SCNetworkReachabilityContext;
|
SCNetworkReachabilitySetCallback 给客户端指定对应target(该参数和需要检测网络状况的地址有一定关联,此处使用的是self.networkReachability),然后当这个target的网络状态变化时,告之SCNetworkReachabilityCallBack对象callBack处理(此处使用的是AFNetworkReachabilityCallback),另外callBack中使用到的参数包括target和context提供的info。
1 2 3 4 5 6
| Boolean SCNetworkReachabilitySetCallback ( SCNetworkReachabilityRef target, SCNetworkReachabilityCallBack __nullable callout, SCNetworkReachabilityContext * __nullable context )
|