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