AFNetworking源码解析系列(1)

569 阅读5分钟

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的源码还是比较容易理解的,只要有点耐心,逻辑还是很容易理通的。