美文网首页iOS 修炼之路iOS开发iOS 开发
AFNetworking 3.0 源码解析之Reachabili

AFNetworking 3.0 源码解析之Reachabili

作者: SemyonXu | 来源:发表于2016-10-07 21:38 被阅读288次

    Reachability这部分主要负责网络的状态网络状态的监听。

    首先介绍下使用方法。

    这里介绍三种使用方法:

    直接使用单利,调用

        AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
        [reachabilityManager startMonitoring];
        [reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            NSLog(@"status %ld", (long)status);
        }];
    

    使用AFURLSessionManager的属性调用

      AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://www.baidu.com"] sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
        [sessionManager.reachabilityManager startMonitoring];
        [sessionManager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            NSLog(@"status %ld", (long)status);
        }];
    

    使用通知中心的模式,监听

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityCallBack:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
    
    
    - (void)reachabilityCallBack:(NSNotification *)sender {
        NSDictionary *userInfo = sender.userInfo;
        AFNetworkReachabilityStatus netStatus = [userInfo[@"AFNetworkingReachabilityNotificationStatusItem"] integerValue];
        NSLog(@"netStatus %ld ", netStatus);
    }
    

    使用方法还是比较简单的。

    下面分析下源码

    初始化网络监听

    + (instancetype)sharedManager;
    
    + (instancetype)manager;
    
    + (instancetype)managerForDomain:(NSString *)domain;
    
    + (instancetype)managerForAddress:(const void *)address;
    
    - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
    

    以上均是初始化方法,我们可以直接用单利模式,比较方便的进行初始化对象,也可以直接用manager,建议还是用单利,因为单利里面也是调用的manager:

    + (instancetype)sharedManager {
        static AFNetworkReachabilityManager *_sharedManager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _sharedManager = [self manager];
        });
    
        return _sharedManager;
    }
    

    manager是直接使用的managerForAdress方法:

    + (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];
    }
    

    当然我们也可以使用初始化domain的方法,然后转换成SCNetworkReachabilityRef对象,进行初始化:

    + (instancetype)managerForDomain:(NSString *)domain {
        SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
    
        AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
        
        CFRelease(reachability);
    
        return manager;
    }
    

    初始化方法里面只是做了一个retain,和初始化网络状态,目测SCNetworkReachabilityRef是不支持自动内存管理的。

    - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
       self = [super init];
       if (!self) {
           return nil;
       }
    
       _networkReachability = CFRetain(reachability);
       self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
    
       return self;
    }
    

    开始监听网络状态

    我们之间调用startMonitoring方法,进行开始网络状态的监控:

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

    使用方法比较简单,此处我们可以看到,做了数据保护工作,如果没有初始化会return,首先先stopMonitoring,这样做可以避免生成多个监听网络的对象,导致收到多个成功的回调。
    然后是一个网络状态捕获到的回调。
    下面才是使用的SystemConfiguration框架下的SCNetworkReachability的API来做的处理,使用也比较简单,先初始化,然后设置回调block,再对回调的C数据转换成网络状态的枚举类型,最后放到了RunLoop里面,设置到了主RunLoop,并设置model为CommonModes,CommonModes就是普通的和事件处理Mode的集合,不清楚的可以去看RunLoop相关文档。

    结束监听网络状态

    结束也比较简单,当然,我们可以自己调用,也可以不调用。因为在类销毁的时候,dealloc中也调用了这个方法。

    - (void)stopMonitoring {
        if (!self.networkReachability) {
            return;
        }
    
        SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    }
    

    再看一下网络状态的枚举,也就是我们可以捕获到的网络状态有哪些:

    typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
        AFNetworkReachabilityStatusUnknown          = -1,
        AFNetworkReachabilityStatusNotReachable     = 0,
        AFNetworkReachabilityStatusReachableViaWWAN = 1,
        AFNetworkReachabilityStatusReachableViaWiFi = 2,
    };
    

    默认是Unknown未知,然后是网络不可达,无线广域网链接,WiFi链接,此处没有区分2G/3G/4G,所以需要使用的小伙伴还得自行处理。

    当然AF也为我们提供了获取的属性方法,我们可以直接调用:

    @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
    
    /**
     Whether or not the network is currently reachable via WWAN.
     */
    @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
    
    /**
     Whether or not the network is currently reachable via WiFi.
     */
    @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
    

    实现:

    - (BOOL)isReachable {
        return [self isReachableViaWWAN] || [self isReachableViaWiFi];
    }
    
    - (BOOL)isReachableViaWWAN {
        return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
    }
    
    - (BOOL)isReachableViaWiFi {
        return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
    }
    

    我们可以看到,我们可以拿到网络是不是可达,当前是不是状态WWAN,WiFi。使用比较方便。

    基本就是这些了,如果文中有什么错误,欢迎大家指正。

    更多问题讨论欢迎加QQ群:200792066

    转载请注明出处:http://semyonxu.com

    相关文章

      网友评论

        本文标题:AFNetworking 3.0 源码解析之Reachabili

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