该文章阅读的AFNetworking的版本为3.2.0。html
该类主要是用来检测网络环境的变化。ios
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
复制代码
这个枚举提供了能够监控的网络状态:bash
AFNetworkReachabilityStatusUnknown
网络状态未知 AFNetworkReachabilityStatusNotReachable
网络状态无链接 AFNetworkReachabilityStatusReachableViaWWAN
网络状态为蜂窝移动网络链接 AFNetworkReachabilityStatusReachableViaWiFi
网络状态为无线局域网链接网络
/**
当前网络链接状态
*/
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
/**
当前是否有网络链接
*/
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
/**
当前网络链接状态是否为蜂窝移动网络链接
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
/**
当前网络链接状态是否为无线局域网链接
*/
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
复制代码
/**
获取单例对象
*/
+ (instancetype)sharedManager;
/**
实例化默认socket地址的对象,并主动监视默认socket地址的状态
*/
+ (instancetype)manager;
/**
实例化指定域的对象,并主动监视指定域的状态
*/
+ (instancetype)managerForDomain:(NSString *)domain;
/**
实例化指定socket地址的对象,并主动监视指定socket地址的状态
*/
+ (instancetype)managerForAddress:(const void *)address;
/**
以指定SCNetworkReachabilityRef对象进行初始化,并主动监视指定SCNetworkReachabilityRef对象的状态
*/
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
/**
初始化方法,这个方法被手动禁止了,若是强制调用这个方法就会报错
*/
- (nullable instancetype)init NS_UNAVAILABLE;
/**
开始监控网络状态
*/
- (void)startMonitoring;
/**
中止监控网络状态
*/
- (void)stopMonitoring;
/**
得到网络状态的本地文字描述
*/
- (NSString *)localizedNetworkReachabilityStatusString;
/**
当网络状态发生变化时,会回调block
*/
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
复制代码
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
复制代码
这两个常量是用在经过通知来监听网络状态变化。当须要用通知来监听网络状态变化时,先监听AFNetworkingReachabilityDidChangeNotification
通知,而后在通知调用的方法中获取传递过来参数中的属性userInfo
,这个属性是NSDictionary
类型的,经过key值AFNetworkingReachabilityNotificationStatusItem
就能够得到当前的网络状态。并发
FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
复制代码
这个方法的做用是将传入的网络状态枚举值转成本地文字描述。dom
NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
复制代码
为.h
文件中全局静态常量赋值异步
typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
复制代码
为参数为AFNetworkReachabilityStatus
类型无返回值的block起名为AFNetworkReachabilityStatusBlock
socket
/**
这个方法就是.h文件最后一个方法的实现,用来将传入的网络状态枚举值转成本地文字描述
*/
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);
}
}
/**
该方法是将SCNetworkReachabilityFlags类型的枚举转换成AFNetworking自定义的网络状态枚举
*/
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;
}
/**
为了保证网络状态变化时block回调和发送通知的统一性,将二者在主线程统一调用
*/
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
// 将flags转成自定义网络状态枚举值
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];
});
}
/**
将上面的方法封装,做为参数传入网络状态监控回调方法SCNetworkReachabilitySetCallback中
*/
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
/**
将block复制到堆中,并封装成方法做为参数构建SCNetworkReachabilityContext结构体
*/
static const void * AFNetworkReachabilityRetainCallback(const void *info) {
return Block_copy(info);
}
/**
释放复制到堆中的block,并封装成方法做为参数构建SCNetworkReachabilityContext结构体
*/
static void AFNetworkReachabilityReleaseCallback(const void *info) {
if (info) {
Block_release(info);
}
}
复制代码
/**
保存传入的SCNetworkReachabilityRef对象
*/
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
/**
保存当前网络状态的枚举值
*/
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
/**
保存传入的用于回调的block
*/
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
复制代码
+ (instancetype)sharedManager {
// 调用以默认socket地址实例化对象的方法,生成单例对象
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [self manager];
});
return _sharedManager;
}
+ (instancetype)managerForDomain:(NSString *)domain {
// 利用传入的域生成SCNetworkReachabilityRef对象
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
// 利用SCNetworkReachabilityRef对象实例化AFNetworkReachabilityManager对象
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
// 释放SCNetworkReachabilityRef对象
CFRelease(reachability);
return manager;
}
+ (instancetype)managerForAddress:(const void *)address {
// 利用传入的地址象实例化AFNetworkReachabilityManager对象
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
// 利用SCNetworkReachabilityRef对象实例化AFNetworkReachabilityManager对象
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
// 释放SCNetworkReachabilityRef对象
CFRelease(reachability);
return manager;
}
+ (instancetype)manager
{
// 根据版本号适配IPv6和IPv4,得到默认地址
#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];
}
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
if (!self) {
return nil;
}
// 保存或初始化属性
_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
return self;
}
- (instancetype)init NS_UNAVAILABLE
{
return nil;
}
- (void)dealloc {
// 中止监控
[self stopMonitoring];
// 释放SCNetworkReachabilityRef对象
if (_networkReachability != NULL) {
CFRelease(_networkReachability);
}
}
- (BOOL)isReachable {
return [self isReachableViaWWAN] || [self isReachableViaWiFi];
}
- (BOOL)isReachableViaWWAN {
return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
}
- (BOOL)isReachableViaWiFi {
return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
}
- (void)startMonitoring {
// 先中止以前的网络监控
[self stopMonitoring];
// 若是没有传入或者生成SCNetworkReachabilityRef对象就直接返回
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);
// 在全局并发队列中异步监听SCNetworkReachabilityRef对象的网络状态,若是发生变化则进行回调和发送通知
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}
- (void)stopMonitoring {
// 若是没有传入或者生成SCNetworkReachabilityRef对象就直接返回
if (!self.networkReachability) {
return;
}
// 将SCNetworkReachabilityRef对象从运行循环中移除
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
- (NSString *)localizedNetworkReachabilityStatusString {
return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
}
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}
复制代码
这其中有一点是在使用GCD时传入了参数DISPATCH_QUEUE_PRIORITY_BACKGROUND
,这个不经常使用的参数有着和AFURLRequestSerialization
类中的throttleBandwidthWithPacketSize:delay:
方法共同的知识点,感兴趣的话能够看这篇文章async
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
return [NSSet setWithObject:@"networkReachabilityStatus"];
}
return [super keyPathsForValuesAffectingValueForKey:key];
}
复制代码
添加依赖键,使reachable
、reachableViaWWAN
和reachableViaWiFi
属性依赖于networkReachabilityStatus
属性,当networkReachabilityStatus
属性值发生变化时,reachable
、reachableViaWWAN
和reachableViaWiFi
属性的观察者也能获得通知。oop
源码阅读系列:AFNetworking
源码阅读:AFNetworking(二)——AFURLRequestSerialization
源码阅读:AFNetworking(三)——AFURLResponseSerialization
源码阅读:AFNetworking(四)——AFSecurityPolicy
源码阅读:AFNetworking(五)——AFNetworkReachabilityManager
源码阅读:AFNetworking(六)——AFURLSessionManager
源码阅读:AFNetworking(七)——AFHTTPSessionManager
源码阅读:AFNetworking(八)——AFAutoPurgingImageCache
源码阅读:AFNetworking(九)——AFImageDownloader
源码阅读:AFNetworking(十)——AFNetworkActivityIndicatorManager
源码阅读:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking
源码阅读:AFNetworking(十二)——UIButton+AFNetworking
源码阅读:AFNetworking(十三)——UIImageView+AFNetworking
源码阅读:AFNetworking(十四)——UIProgressView+AFNetworking