AFNetworkReachabilityManager目录
AFNetworkReachabilityManager概述
AFNetworkReachabilityManager是AFN封装了系统的SystemConfiguration的API做出的关于网络状态监测的类。
AFN提供的网络状态枚举如下:
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1, //未知状态
AFNetworkReachabilityStatusNotReachable = 0, //不可达
AFNetworkReachabilityStatusReachableViaWWAN = 1, //蜂窝数据
AFNetworkReachabilityStatusReachableViaWiFi = 2, //WiFi
};
我们不能根据不可达这种状态就放弃发送网络请求,正如AFN本身所述:
Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it’s possible that an initial request may be required to establish reachability. (网络状态不可以用来阻止用户发起请求,因为有可能这个请求就是用来判断网络状态的)
AFNetworkReachabilityManager.h
网络状态描述
AFNetworkReachabilityStatus networkReachabilityStatus;
BOOL reachable;
BOOL reachableViaWWAN;
BOOL reachableViaWiFi;
初始化方法
+ (instancetype)sharedManager;
+ (instancetype)manager;
//只针对一个domain监控
+ (instancetype)managerForDomain:(NSString *)domain;
+ (instancetype)managerForAddress:(const void *)address;
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
设置与监听
//必须调用这个方法才能有网络状态变化的通知与回调
- (void)startMonitoring;
- (void)stopMonitoring;
- (NSString *)localizedNetworkReachabilityStatusString;
//网络发生变化时Block回调
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
AFNetworkReachabilityManager.m
AFN封装的本地化网络状态描述
NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusNotReachable:
return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil);
case AFNetworkReachabilityStatusReachableViaWWAN:
return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil);
case AFNetworkReachabilityStatusReachableViaWiFi:
return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil);
case AFNetworkReachabilityStatusUnknown:
default:
return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil);
}
}
- (NSString *)localizedNetworkReachabilityStatusString {
return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
}
判断网络状态
static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
//网络可达
BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
//需要连接
BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
//可以自动连接
BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
//无需用户操作即可连接
BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
if (isNetworkReachable == NO) {
status = AFNetworkReachabilityStatusNotReachable;
}
#if TARGET_OS_IPHONE
else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
status = AFNetworkReachabilityStatusReachableViaWWAN;
}
#endif
else {
status = AFNetworkReachabilityStatusReachableViaWiFi;
}
return status;
}
状态变化通知
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
//主线程发送网络状态通知
dispatch_async(dispatch_get_main_queue(), ^{
//首先进行Block回调操作
if (block) {
block(status);
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
});
}
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
//这里如果设置了会在出现网络状态变化的时候回调
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}
监测和停止监测
- (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;
//用户设置的Block回调
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
/* 新建上下文: user-specified data and callbacks for SCNetworkReachability.
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;
*/
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
/* 设置回调: Assigns a client to a target, which receives callbacks when the reachability of the target changes.
Boolean SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
SCNetworkReachabilityCallBack __nullable callout,
SCNetworkReachabilityContext * __nullable context);
*/
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
//加入RunLoop: Schedules the given target with the given run loop and mode.
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
//异步线程 发送一次当前的网络状态
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
//SCNetworkReachabilityGetFlags: Determines if the given target is reachable using the current network configuration.
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
AFNetworkReachabilityManager总结
AFNetworkReachabilityManager实际上对系统库进行了封装,提供了简洁方便的用法和API。AFNetworkReachabilityManager的主要方法在于startMonitoring以及之后的状态通知,至于具体怎么判断网络状态是另一个话题。
- 关于回调
// Assigns a client to a target, which receives callbacks when the reachability of the target changes.
Boolean SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target,
SCNetworkReachabilityCallBack __nullable callout,
SCNetworkReachabilityContext * __nullable context);
AFNetworkReachabilityCallback
上面的方法传入的这个Block实际是在接受系统回调和发送通知。
AFPostReachabilityStatusChange中实现了获取真实状态,callback修改networkReachabilityStatus属性,并在主线程发送网络状态变化的通知。setReachabilityStatusChangeBlock
用户如果自己设置了回调的Block则会在callback这个Block中回调当前的状态。