AFNetworkReachabilityManager
AFNetworkReachabilityManager
是用来监测网络状态的类。设置状态改变回调方法,当网络状态改变时获得当前网络状态回调过来。
网络的状态值有以下四种:
ypedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,// 未知
AFNetworkReachabilityStatusNotReachable = 0, // 不可用
AFNetworkReachabilityStatusReachableViaWWAN = 1, // 无线广域网连接
AFNetworkReachabilityStatusReachableViaWiFi = 2, // WiFi连接
};
AFNetworkReachabilityManager
提供了五种初始化的方法。
可以通过单例方法初始化
+ (instancetype)sharedManager {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 调用+ manager初始化方法
_sharedManager = [self manager];
});
return _sharedManager;
}
单例里面调用了第二种通过默认的socket地址初始化方法,返回一个manager对象,sin_family表示协议族,AF_INET表示TCP/IP协议族的地址
+ (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
// 声明sockaddr_in结构体
struct sockaddr_in address;
// address清零
bzero(&address, sizeof(address));
// address赋值
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
#endif
// 调用+ [managerForAddress:]方法
return [self managerForAddress:&address];
}
在这里又调用了第三种通过传入一个socket地址来初始化
+ (instancetype)managerForAddress:(const void *)address {
// 生成SCNetworkReachabilityRef
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
// 调用- [initWithReachability:]方法
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
里面又调用了第五种初始化方法,因为该方法的后缀里面有NS_DESIGNATED_INITIALIZER
,所以最终都会调到它,这里就是做了初始化的工作,将起始的网络状态定为Unknown
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
if (!self) {
return nil;
}
_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
return self;
}
最后剩下一种方法就是可以根据特定的域来初始化
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
然后在初始化结束之后,我们需要设置网络状态改变的回调,在开启监听之后,会将网络状态回调给外部
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}
最后就是开启监听
- (void)startMonitoring {
// 停止监听
[self stopMonitoring];
if (!self.networkReachability) {
return;
}
// 收到callback调用后,将status通过networkReachabilityStatusBlock回调出去
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
// 声明SCNetworkReachabilityContext结构体
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
// 设置回调
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
// 加到Main runloop里面对其进行监测
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
// 获取当前的网络状态,调用callback
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}
如果没有设置回调的话,也可以通过注册通知的方式,收到网络状态的变化
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
// 获取当前的status
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
dispatch_async(dispatch_get_main_queue(), ^{
// 返回status值
if (block) {
block(status);
}
// 同时会发送一个通知
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
});
}
停止监听的话,就是取消在Main Runloop里面的监听
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
具体使用方法就如下:
AFNetworkReachabilityManager *networkManager = [AFNetworkReachabilityManager sharedManager];
[networkManager startMonitoring];
[networkManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusNotReachable:
// do something
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
// do something
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
// do something
break;
default:
break;
}
}];