AFNetworking 3.0 源码解析之Reachability

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

这里介绍下使用方法。

1.直接使用单利,调用

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

2.使用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);  
  }];  

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

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

使用方法还是比较简单的

下面分析下源码。

1.初始化网络监听

+ (instancetype)sharedManager;  

+ (instancetype)manager;  

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

+ (instancetype)managerForAddress:(const voidvoid *)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;  
}  

2.开始监听网络状态
我们之间调用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 voidvoid *)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相关文档。

3.结束监听网络状态

结束也比较简单,当然,我们可以自己调用,也可以不调用。因为在类销毁的时候,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。使用比较方便。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值