AFNetworking主要包含四个部分:
1.Reachability
2.Security
3.Serialization
4.NSURLSession
其中前三个部分是彼此独立的模块,互相无依赖,NSURLSession模块依赖于前三部分,
现在我们就一个模块一个模块的分别解析,本文首先解析Reachability网络监测部分的源码。
作为一个实用主义者,我本人是喜欢直接看代码,看不懂的地方再看解释,所以下面会以代码为主。AFNetworkReachabilityManager.h源码展示:
#import <Foundation/Foundation.h>
#if !TARGET_OS_WATCH
//SystemConfiguration.famework中提供和联网相关的方法,可用来监测网络连接状况
#import <SystemConfiguration/SystemConfiguration.h>
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
NS_ASSUME_NONNULL_BEGIN
@interface AFNetworkReachabilityManager : NSObject
//当前的网络连接状态
@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
//当前网络是否连接
@property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable;
//当前网络连接的是否为蜂窝数据
@property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN;
//当前网络连接的是否为WiFi
@property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi;
#pragma 初始化方法-----------------------------------------------------------------------------
//单例对象,内部调用的是+ (instancetype)manager方法
+ (instancetype)sharedManager;
//根据默认的socket address创建一个manager对象
+ (instancetype)manager;
//根据指定域名初始化一个manager对象
+ (instancetype)managerForDomain:(NSString *)domain;
//根据指定的socket address初始化一个manager对象
+ (instancetype)managerForAddress:(const void *)address;
//根据指定的SCNetworkReachabilityRef对象来初始化一个manager对象,为指定初始化方法
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
//禁用new方法
+ (instancetype)new NS_UNAVAILABLE;
// 禁用init方法,如果调用这个方法,会抛出异常
- (instancetype)init NS_UNAVAILABLE;
#pragma 提供的公开方法供外部调用-----------------------------------------------------------------------------
//开始检测网络状况,设置网络监测的回调之前要先调用这个方法
- (void)startMonitoring;
//停止检测网络状况- (void)stopMonitoring;
// 返回一个本地化字符串来展示当前的网络连接状态
- (NSString *)localizedNetworkReachabilityStatusString;
//当网络检测状态发生改变时的回调,也是我们最经常调用的方法
- (void)setReachabilityStatusChangeBlock:(nullable void (^)(AFNetworkReachabilityStatus status))block;
@end
//网路状态改变发出的通知
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;//AFNetworkingReachabilityDidChangeNotification通知的userInfo中status对象的key
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;// 返回一个本地化字符串来展示当前的网络连接状态 和- (NSString *)localizedNetworkReachabilityStatusString一样
FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
NS_ASSUME_NONNULL_END
#endif
AFNetworkReachabilityManager.m源码展示:
#import "AFNetworkReachabilityManager.h"
#if !TARGET_OS_WATCH
#import <netinet/in.h>
#import <netinet6/in6.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#pragma 定义的一些固定方法来方便操作===================================================================================
NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";
NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem";
typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
//返回一个本地化字符串来展示当前的网络连接状态
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:保存返回的测试连接状态
将系统的SCNetworkReachabilityFlags转换为我们自定义的AFNetworkReachabilityStatus
*/
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;
}
//网络监测状态发生变化时的回调,以及AFNetworkingReachabilityDidChangeNotification通知的创建和发送
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
dispatch_async(dispatch_get_main_queue(), ^{
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);
}
//内存管理相关,retain
static const void * AFNetworkReachabilityRetainCallback(const void *info) {
return Block_copy(info);
}
//内存管理相关,release
static void AFNetworkReachabilityReleaseCallback(const void *info) {
if (info) {
Block_release(info);
}
}
@interface AFNetworkReachabilityManager ()
//用来保存创建测试连接返回的引用
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
@end
@implementation AFNetworkReachabilityManager
+ (instancetype)sharedManager {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [self manager];
});
return _sharedManager;
}
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
+ (instancetype)managerForAddress:(const void *)address {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
+ (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];
}
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
if (!self) {
return nil;
}
_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
return self;
}
- (instancetype)init
{
@throw [NSException exceptionWithName:NSGenericException
reason:@"`-init` unavailable. Use `-initWithReachability:` instead"
userInfo:nil];
return nil;
}
- (void)dealloc {
[self stopMonitoring];
//销毁时将_networkReachability对象释放
if (_networkReachability != NULL) {
CFRelease(_networkReachability);
}
}
#pragma mark -
- (BOOL)isReachable {
return [self isReachableViaWWAN] || [self isReachableViaWiFi];
}
- (BOOL)isReachableViaWWAN {
return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN;
}
- (BOOL)isReachableViaWiFi {
return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi;
}
#pragma mark -
- (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 void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
//设置回调
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
//加入Runloop池中
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);
}
});
}
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
//停止网络监听
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
#pragma mark -
- (NSString *)localizedNetworkReachabilityStatusString {
return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus);
}
#pragma mark -
- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block {
self.networkReachabilityStatusBlock = block;
}
#pragma mark - NSKeyValueObserving
/*
这个是键值依赖,因为reachable,reachableViaWWAN,reachableViaWiFi的属性都和networkReachabilityStatus的属性有关,所以当你使用KVO监听这三个属性
时,networkReachabilityStatus的值一旦改变,也会触发这三个属性的改变,接下来我会专门写一个专题为大家介绍KVO的详情
*/
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) {
return [NSSet setWithObject:@"networkReachabilityStatus"];
}
return [super keyPathsForValuesAffectingValueForKey:key];
}
@end
#endif
如何使用AFNetworkReachabilityManager这个类进行网络监听:
第一种方法,使用block回调:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
[manager startMonitoring];
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(@"%@",AFStringFromNetworkReachabilityStatus(status));
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
break;
case AFNetworkReachabilityStatusNotReachable:
break;
case AFNetworkReachabilityStatusUnknown:
default:
break;
}
}];
return YES;
}
第二种方法,使用通知:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
[manager startMonitoring];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkStatuChange:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
return YES;
}
-(void)networkStatuChange:(NSNotification *)noti
{
AFNetworkReachabilityStatus status =[noti.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue];
NSLog(@"%@",AFStringFromNetworkReachabilityStatus(status));
}其实AFNetworkReachabilityManager的源码还是比较容易理解的,只要有点耐心,逻辑还是很容易理通的。