【AFNetworking 分析】AFNetworkReachabilityManager 网络状态监控

原创
2021/02/09 15:44
阅读数 405

Pre

  • AFNetworking分析版本:4.0.1

基础

简介

  • AFNetworkReachabilityManager监控domains的可达性,以及WWAN和WiFi网络接口的地址。
  • Reachability可用于确定关于网络操作失败原因的后台信息,或在建立连接时触发网络操作重试。它不应该用来阻止用户初始化网络请求,因为可能需要初始化请求来建立可达性。
  • 在确定可达性状态之前,AFNetworkReachabilityManager的实例必须用-startMonitoring启动。

框架

使用demo

  1. 初始化一个manager对象
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager managerForDomain:@"localhost"];
  1. 设置网络状态变化回调block
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
	···
	//可以根据不同状态进行自己的操作
    }];
  1. 开启监控
[manager startMonitoring];
  1. 关闭监控
[manager stopMonitoring];

源码分析

初始化

  • 根据前面的框架图我们可以看到AFNetworkReachabilityManager共有5个初始化方法
  • sharedManager会调用manager方法创建一个单例并返回,以下着重分析剩下4个初始化方法

+ (instancetype)manager;

  1. 分配socket地址
    //基于ipv6
    struct sockaddr_in6 address;
    bzero(&address, sizeof(address));
    address.sin6_len = sizeof(address);
    address.sin6_family = AF_INET6;
    //基于ipv4
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_len = sizeof(address);
    address.sin_family = AF_INET;

e.g. 基于ipv6 模拟器

2. 调用managerForAddress:方法创建实例并返回

+ (instancetype)managerForAddress:(const void *)address;

  1. 调用SCNetworkReachabilityCreateWithAddress:方法,传入socket地址,创建一个SCNetworkReachabilityRefC对象
SCNetworkReachabilityRef reachability = 
	SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);

// kCFAllocatorDefault为NULL
// SCNetworkReachabilityCreateWithAddress
SCNetworkReachabilityRef __nullable SCNetworkReachabilityCreateWithAddress (
	CFAllocatorRef __nullable	allocator,
	const struct sockaddr *address
)
  1. 调用initWithReachability:,传入步骤1中创建的reachability进行初始化并返回

+ (instancetype)managerForDomain:(NSString *)domain;

  1. 调用SCNetworkReachabilityCreateWithName:方法,传入域名,创建一个SCNetworkReachabilityRefC对象
SCNetworkReachabilityRef reachability = 
	SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
// SCNetworkReachabilityCreateWithName
SCNetworkReachabilityRef __nullable SCNetworkReachabilityCreateWithName(
	CFAllocatorRef __nullable allocator,
	const char *nodename
)
  1. 调用initWithReachability:,传入步骤1中创建的reachability进行初始化并返回

- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability ;

  1. 将传入的reachability赋值给AFNetworkReachabilityManagernetworkReachability属性。(此处仅引用该reachability对象,避免其被提前释放,使用CFReatin增加引用计数)
_networkReachability = CFRetain(reachability);
  1. 设置默认网络状态为未知
  2. 返回实例

说明

  • 由上述源码分析我们可以看出来,每次调用manager创建的对象都不同,而调用sharedManager则会再次创建一个新对象(仅创建一次),如下图所示

监听

stopMonitoring 停止监听

  1. 若当前对象的网络监控属性SCNetworkReachabilityRef为空,直接返回(保证误调用不会出错)
if (!self.networkReachability) {
    return;
}
  1. 调用SCNetworkReachability的接口取消之前在 main Runloop 中的监听
 SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);

startMonitoring 开始监听

  1. 停止已设置过的监听
  2. 创建一个每次网络状态变化的监听block
    2.1 重新设置当前对象存储的网络状态
    2.2 调用之前setReachabilityStatusChangeBlock设置的block对网络状态进行处理
if (strongSelf.networkReachabilityStatusBlock) {
    strongSelf.networkReachabilityStatusBlock(status);
}
  1. 创建context对象(一个包含用户指定数据和SCNetworkReachability的回调的结构体)
SCNetworkReachabilityContext context = {0,
				(__bridge void *)callback, 
				AFNetworkReachabilityRetainCallback,
				AFNetworkReachabilityReleaseCallback,
				NULL};
  1. 当SCNetworkReachabilityRef目标的网络状态变化时,分配一个client给目标,接收回调
SCNetworkReachabilitySetCallback(self.networkReachability,
				AFNetworkReachabilityCallback, 
				&context);
  1. 将当前SCNetworkReachabilityRef目标添加到main runloopkCFRunLoopCommonModes模式中

SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, 
					CFRunLoopGetMain(),
					kCFRunLoopCommonModes);
  1. 后台异步执行:若当前SCNetworkReachabilityRef目标可达,发送当前网络状态
AFPostReachabilityStatusChange(flags, callback);
  • AFPostReachabilityStatusChange a. 将flags转化为status
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);

b. 主线程异步执行: - 获取当前AFNetworkReachabilityManager对象 - 发送网络状态变化的通知(AFNetworkingReachabilityDidChangeNotification

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:manager userInfo:userInfo];
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部