美文网首页
AFNetworkReachabilityManager解析

AFNetworkReachabilityManager解析

作者: silasjs | 来源:发表于2019-07-16 14:14 被阅读0次

    AFNetworkReachabilityManager解析

    使用方法

    //创建
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
    
    //设置回调
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"不明网络");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"没有网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"蜂窝网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WiFi"); 
                break;
            default:
                break;
        }
    }];
     
    //开始监听
    [manager startMonitoring];
    

    解析

    一图概千言,先有个大致了解,后面可以慢慢品味。

    网络状态监听流程.png

    AFNetworkReachabilityManager的创建

    AFNetworkReachabilityManager对外提供了两种创建方式:

    + (instancetype)sharedManager;
    
    + (instancetype)manager;
    

    从这两个接口的实现中可以看出sharedManager是个单例模式,内部使用manager创建了AFNetworkReachabilityManager对象。一般我们不会只监听一次网络状态,大多都是使用单例模式创建的。

    再看看具体的创建过程:

    1. 根据不同的系统环境,来定义socked地址。然后调用managerForAddress继续下一步。
      1. iOS9或者macOS10.11.0,使用ipv6的网络,sockaddr_in6结构体
      2. 低版本使用ipv4网络,sockaddr_in结构体
    + (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)
        //基于ipv6
        struct sockaddr_in6 address;
        bzero(&address, sizeof(address));
        address.sin6_len = sizeof(address);
        address.sin6_family = AF_INET6;
    #else
        //基于ipv4
        struct sockaddr_in address;
        bzero(&address, sizeof(address));
        address.sin_len = sizeof(address);
        address.sin_family = AF_INET;
    #endif
        return [self managerForAddress:&address];
    }
    
    1. socked地址只是为了创建SystemConfiguration框架中的SCNetworkReachabilityRef引用。SCNetworkReachabilityRef才是AFNetworkReachabilityManager用来监听网络状态的对象。
    + (instancetype)managerForAddress:(const void *)address {
        SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
        
        AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    
        CFRelease(reachability);
        
        return manager;
    }
    
    1. 初始化并设置默认状态为AFNetworkReachabilityStatusUnknown
    - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
        self = [super init];
        if (!self) {
            return nil;
        }
    
        //去引用这个对象,不会有所有权,如果为了避免这个对象被释放,可以通过(CFRetain)去添加引用计数
        _networkReachability = CFRetain(reachability);
        //设置默认状态
        self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
    
        return self;
    }
    

    监听网络状态

    主要还是使用SCNetworkReachability来进行监听。

    • 创建上下文SCNetworkReachabilityContext:保存回调函数以及相关的一些数据操作

      • 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;
        
      • 结构体的第一个元素为版本号:0

      • info:回调函数(用户调用)

      • 第三个是对info做retain操作的函数

      • 第四个是对info做release操作的函数

      • info函数的描述信息

    • 设置回调函数SCNetworkReachabilitySetCallback

      • Boolean
        SCNetworkReachabilitySetCallback        (
                                SCNetworkReachabilityRef            target,
                                SCNetworkReachabilityCallBack   __nullable  callout,
                                SCNetworkReachabilityContext    * __nullable    context
                                )               API_AVAILABLE(macos(10.3), ios(2.0));
        
      • target:回调函数callout的调用对象。

      • callout:状态改变时SCNetworkReachabilityRef调用

      • context:上下文

    • 添加主运行循环中执行SCNetworkReachabilityScheduleWithRunLoop

    - (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);
            }
        });
    }
    

    然后当状态发生变化时,SCNetworkReachabilityRef就会调用AFNetworkReachabilityCallback进行回调。告诉AFN当前的网络可达标识和AFN回调给外界的callback(也就是上下文SCNetworkReachabilityContext中的void *info)。

    static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
        AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
    }
    

    AFPostReachabilityStatusChange中把SCNetworkReachabilityFlags转为AFNetworkReachabilityStatus后回调给外界。

    相关文章

      网友评论

          本文标题:AFNetworkReachabilityManager解析

          本文链接:https://www.haomeiwen.com/subject/egzzkctx.html