AFNetworkReachabilityManager是用来监测网络状态的类,可以通过设置状态改变回调来获得当前网络状态

网络的状态值有以下四种

1
2
3
4
5
6
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,// 未知
AFNetworkReachabilityStatusNotReachable = 0, // 不可用
AFNetworkReachabilityStatusReachableViaWWAN = 1, // 无线广域网连接
AFNetworkReachabilityStatusReachableViaWiFi = 2, // WiFi连接
};

AFNetworkReachabilityManager提供了五种初始化的方法

可以通过单例方法初始化

1
2
3
4
5
6
7
8
9
10
+ (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协议族的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
+ (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地址来初始化

1
2
3
4
5
6
7
8
9
10
+ (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

1
2
3
4
5
6
7
8
9
10
11
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
if (!self) {
return nil;
}

_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;

return self;
}

最后剩下一种方法就是可以根据特定的域来初始化

1
2
3
4
5
6
7
8
9
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);

AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];

CFRelease(reachability);

return manager;
}

然后在初始化结束之后,我们需要设置网络状态改变的回调,在开启监听之后,会将网络状态回调给外部

1
2
3
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}

最后就是开启监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- (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);
}
});
}

如果没有设置回调的话,也可以通过注册通知的方式,收到网络状态的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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里面的监听

1
2
3
4
5
6
7
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}

SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}

使用方式例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
}];