AFNetworking源码解析

//=========================第一部分===============================

在AFN框架中,负责网络请求通讯最重要的两个类AFURLSessionManager、AFHTTPSessionManager。AFHTTPSessionManager又是继承于AFURLSessionManager,进行了封装。

AFURLRequestSerialization结构的类,主要用于网络请求之前的操作配置,负责配置网络请求的请求头部、序列化请求参数

AFURLResponseSerialization结构的类,主要用于网络请求之后的数据处理,针对不同的数据进行处理,比如JSON、XML、plist、图片格式等数据。

AFSecurityPolicy主要用于HTTPS环境下的认证安全请求通讯。如果是通过CA认证过的HTTPS访问地址,使用AFN时只需要拼接上https://即可,AFN的网络请求配置中默认使用CA认证访问HTTPS地址;若是自签的证书时,则需要当前类用于进行认证。

AFNetworkReachabilityManager,用于网络状态的监听,判断是否有网络,以及判断网络连接类型,比如蜂窝网络或WiFi环境。但当前类无法判断当前环境能否访问服务器服务。其原理是利用主机的数据包发送。

10.22.58.png

一、AFURLSessionManager
AFURLSessionManager是AFHTTPSessionManger的基类。它遵循了NSURLSession 和 NSURLSessionTask的一些代理方法,实现了数据的请求、上传和下载功能。

预览一下.h文件,我们可以看到下面这四个只读属性:

@property(readonly,nonatomic,strong)NSArray *tasks;

@property(readonly,nonatomic,strong)NSArray *dataTasks;

@property(readonly,nonatomic,strong)NSArray *uploadTasks;

@property(readonly,nonatomic,strong)NSArray *downloadTasks;

分别代表了总的任务集合、数据任务集合、上传任务集合和下载任务集合。

然后我们再看下几个创建请求任务的方法:

1.创建数据任务

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler;

2.创建上传任务(有三种方法)

通过fileURL方式上传(上传本地文件的URL路径)

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError  * _Nullable error))completionHandler;

通过bodyData方式上传(数据放在请求体httpBody中)

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(nullable NSData *)bodyData
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

通过流方式上传(此时一定要设置setTaskNeedNewBodyStreamBlock回调,否则session没办法在重新发送steam的时候找到数据源)

- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

3.创建下载任务(也有两种方式)

通过http方式普通下载

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                          destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

另一种则是通过之前的下载数据来恢复下载,destination在下载的过程中文件会先存放在一个临时的位置,等到下载完成之后,文件会转移到目标位置

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
                                             destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                       completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;

其他一些方法都是设置请求相关的,比如请求失败策略(是否继续请求),获取上传、下载进度progress等。

再来看下.m实现,实现文件里面具体分为三部分:

第一部分:AFURLSessionManagerTaskDelegate

Delegate里面做的内容有:

1、设置task的progress

2、KVO监听task、progress的方法调用

3、实现URLSessionTask的回调,将完成的结果block给manager里面相关的调用方法,并且通知给接收者

4、对接收到的数据进行了拼接

5、对下载完成后的文件进行转移

第二部分:_AFURLSessionTaskSwizzling

这部分主要做的是将NSURLSessionDataTask及父类里的resume和suspend方法替换成自己自定义的方法

第三部分:AFURLSessionManager

1、初始化session配置及增加task代理,通过self.session getTasks得到所有的任务,然后依次设置代理

2、外部API的block通过delegate里面的block来获得

//===========================第二部分=============================

AFHTTPSessionManager是继承于AFURLSessionManager,提供了几个更方便的http请求的方法,GET、POST、PUT、PATCH、DELETE。在这里我们可以看到他有一个readOnly修饰的baseURL属性,我们可以在二次封装的时候设置成我们项目中要使用的地址(一般我们使用AF的时候都会进行二次封装,这样更方便来满足我们的需求)。

这里我们可以看到下面这几个初始化方法,主要是设置baseURL、requestSerializer和responseSerializer,requestSerializer和responseSerializer我们在接下来的几篇文章里会介绍。

+ (instancetype)manager {
    return [[[self class] alloc] initWithBaseURL:nil];
}
 
- (instancetype)init {
    return [self initWithBaseURL:nil];
}
 
- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}
 
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
 
- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }
 
    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }
 
    self.baseURL = url;
 
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];
 
    return self;
}

然后下面我们可以看到POST、GET、PUT、PATCH、DELETE这五个方法。他们的传参基本都是大同小异,URLString表示请求的URL,parameters表示客户端请求内容的存储器,progress表示请求的进度,constructingBodyWithBlock里面只有一个formData用来拼接到HTTP的请求体,success表示请求成功后的block回调,failure表示请求失败的block回调。那么他们有什么不同呢?

1、POST请求是向服务端发送数据的,用来更新资源信息,它可以改变数据的种类等资源

2、GET请求是向服务端发起请求数据,用来获取或查询资源信息

3、PUT请求和POST请求很像,都是发送数据的,但是PUT请求不能改变数据的种类等资源,它只能修改内容

4、DELETE请求就是用来删除某个资源的

5、PATCH请求和PUT请求一样,也是用来进行数据更新的,它是HTTP verb推荐用于更新的。

这几个方法的实现其实都是下面那个[dataTaskWithHTTPMethod:URLString:parameters:uploadProgress:downloadProgress:success:failure]。传参的内容基本都是和上一层方法一样,method指的就是请求的类型,返回的是NSURLSessionDataTask类型的对象。

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(nullable id)parameters
                                         headers:(nullable NSDictionary  *)headers
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                         failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    for (NSString *headerField in headers.keyEnumerator) {
        [request setValue:headers[headerField] forHTTPHeaderField:headerField];
    }
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
 
        return nil;
    }
 
    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];
 
    return dataTask;
}
//===========================第三部分=============================

AFSecurityPolicy
在iOS9后苹果默认是不能使用HTTP请求的,而AFSecurityPolicy主要的作用就是验证HTTPS请求的证书的有效性。如果你还是想要使用HTTP请求,就需要在plist里面设置NSAppTransportSecurity的NSAllowsArbitraryLoads为true,当然我们首先是推荐使用HTTPS的。

AFSecurityPolicy是安全策略类,有三种SSL Pinning模式。

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,
    AFSSLPinningModePublicKey,
    AFSSLPinningModeCertificate,
};

这个是证书集合,泛型里面表示了集合里面是NSData类型,表明这个是用来存证书数据的集合,这些证书根据SSL Pinning模式来和服务器进行校验,默认是没有证书的,我们需要调用+ certificatesInBundle:方法将bundle里面的证书文件转成里面是data类型的集合

@property (nonatomic, strong, nullable) NSSet  *pinnedCertificates;
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
    // 获取证书
    NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
 
    NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
    // 将证书文件转成data
    for (NSString *path in paths) {
        NSData *certificateData = [NSData dataWithContentsOfFile:path];
        [certificates addObject:certificateData];
    }
 
    return [NSSet setWithSet:certificates];
}

有三种初始化的方法

第一种是默认策略,AFSSLPinningModeNone

+ (instancetype)defaultPolicy {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
 
    return securityPolicy;
}

第二种是自定义一个安全策略,然后读取cer文件放到集合里面

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
    return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
}
+ (NSSet *)defaultPinnedCertificates {
    static NSSet *_defaultPinnedCertificates = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSBundle *bundle = [NSBundle bundleForClass:[self class]];
        _defaultPinnedCertificates = [self certificatesInBundle:bundle];
    });
 
    return _defaultPinnedCertificates;
}

第三种则是需要我们多传入一个证书集合

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = pinningMode;
 
    [securityPolicy setPinnedCertificates:pinnedCertificates];
 
    return securityPolicy;
}

设置证书的时候,就是把上面初始化时传入的证书取出公钥,再把公钥保存到mutablePinnedPublicKeys集合中

- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
    _pinnedCertificates = pinnedCertificates;
 
    if (self.pinnedCertificates) {
        NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
        for (NSData *certificate in self.pinnedCertificates) {
            // 取出公钥
            id publicKey = AFPublicKeyForCertificate(certificate);
            if (!publicKey) {
                continue;
            }
            // 将公钥存到集合
            [mutablePinnedPublicKeys addObject:publicKey];
        }
        self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
    } else {
        self.pinnedPublicKeys = nil;
    }
}

在AFPublicKeyForCertificate方法里面,做了一系列操作后返回公钥,如下:

static id AFPublicKeyForCertificate(NSData *certificate) {
    id allowedPublicKey = nil;
    SecCertificateRef allowedCertificate;
    SecCertificateRef allowedCertificates[1];
    CFArrayRef tempCertificates = nil;
    SecPolicyRef policy = nil;
    SecTrustRef allowedTrust = nil;
    SecTrustResultType result;
 
    // 取出证书SecCertificateRef
    allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
    __Require_Quiet(allowedCertificate != NULL, _out);
    
    // 生成证书数组
    allowedCertificates[0] = allowedCertificate;
    tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
 
    // 生成SecPolicyRef
    policy = SecPolicyCreateBasicX509();
    __Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
    __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
    
    // 从SecPolicyRef中取出公钥
    allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
 
_out:
    // 一些资源的释放
 
    return allowedPublicKey;
}

-[evaluateServerTrust:forDomain:]方法是AFSecurityPolicy类最长也是最重要的方法,它用来验证服务端是否是受信

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(NSString *)domain
{
    // 苹果文档中表示不要隐式地信任自己签名的证书,取而代之的是应该增加自己的CA证书到受信列表里
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
        NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
        return NO;
    }
 
    // policies增加SecPolicyRef
    NSMutableArray *policies = [NSMutableArray array];
    if (self.validatesDomainName) {
        [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    } else {
        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
    }
    
    // 设置信任的policies应当被验证
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
    
    // 向系统内置的根证书验证服务端返回的证书是否合法
    if (self.SSLPinningMode == AFSSLPinningModeNone) {
        return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        return NO;
    }
    
    // 根据SSLPinningMode对服务端是否受信进行校验
    switch (self.SSLPinningMode) {
        case AFSSLPinningModeNone:
        default:
            return NO;
        case AFSSLPinningModeCertificate: {
            NSMutableArray *pinnedCertificates = [NSMutableArray array];
            for (NSData *certificateData in self.pinnedCertificates) {
                [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
            }
            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
 
            if (!AFServerTrustIsValid(serverTrust)) {
                return NO;
            }
 
            // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
            NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
            
            for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                    return YES;
                }
            }
            
            return NO;
        }
        case AFSSLPinningModePublicKey: {
            NSUInteger trustedPublicKeyCount = 0;
            NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
 
            for (id trustChainPublicKey in publicKeys) {
                for (id pinnedPublicKey in self.pinnedPublicKeys) {
                    if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                        trustedPublicKeyCount += 1;
                    }
                }
            }
            return trustedPublicKeyCount > 0;
        }
    }
    
    return NO;
}
//===========================第四部分=============================

AFNetworkReachabilityManager
AFNetworkReachabilityManager是用来监测网络状态的类。设置状态改变回调方法,当网络状态改变时获得当前网络状态回调过来。

网络的状态值有以下四种:

ypedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
    AFNetworkReachabilityStatusUnknown          = -1,// 未知
    AFNetworkReachabilityStatusNotReachable     = 0, // 不可用
    AFNetworkReachabilityStatusReachableViaWWAN = 1, // 无线广域网连接
    AFNetworkReachabilityStatusReachableViaWiFi = 2, // WiFi连接
};
AFNetworkReachabilityManager提供了五种初始化的方法。

可以通过单例方法初始化

+ (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协议族的地址

+ (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地址来初始化

+ (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

- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
    self = [super init];
    if (!self) {
        return nil;
    }
 
    _networkReachability = CFRetain(reachability);
    self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
 
    return self;
}

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

+ (instancetype)managerForDomain:(NSString *)domain {
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
 
    AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
    
    CFRelease(reachability);
 
    return manager;
}

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

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

最后就是开启监听

- (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);
        }
    });
}

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

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里面的监听

- (void)stopMonitoring {
    if (!self.networkReachability) {
        return;
    }
 
    SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}

具体使用方法就如下:

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;
    }
}];
//===========================第五部分=============================

AFURLRequestSerialization
AFURLRequestSerialization是用来对发出的请求进行一些处理

AFPercentEscapedStringFromString方法将string里面的:#[]@!$&’()*+,;=字符替换成%

NSString * AFPercentEscapedStringFromString(NSString *string) {
    static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
    static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";

    // 从可用字符替换删除掉:#[]@!$&'()*+,;=这些字符
    NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
    [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
 
    // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
    // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
    
    // 声明批量处理的大小为50
    static NSUInteger const batchSize = 50;
 
    NSUInteger index = 0;
    NSMutableString *escaped = @"".mutableCopy;
    
    // 循环将string里面:#[]@!$&'()*+,;=的字符替换成%
    while (index < string.length) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wgnu"
        NSUInteger length = MIN(string.length - index, batchSize);
#pragma GCC diagnostic pop
        NSRange range = NSMakeRange(index, length);
 
        // To avoid breaking up character sequences such as 
        range = [string rangeOfComposedCharacterSequencesForRange:range];
 
        NSString *substring = [string substringWithRange:range];
        NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
        [escaped appendString:encoded];
 
        index += range.length;
    }
 
    return escaped;
}

在AFQueryStringPair类里面有个- URLEncodedStringValue方法,将请求里面的URL参数转成field=value形式

- (NSString *)URLEncodedStringValue {
    if (!self.value || [self.value isEqual:[NSNull null]]) {
        return AFPercentEscapedStringFromString([self.field description]);
    } else {
        return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedStringFromString([self.field description]), AFPercentEscapedStringFromString([self.value description])];
    }
}

字典里面是我们查询的key和value,我们通过将字典内容转成AFQueryStringPair对象,调用- URLEncodedStringValue方法,转成key=value,放到mutablePairs数组里,最后用&符拼接起来

NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
    NSMutableArray *mutablePairs = [NSMutableArray array];
    for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
        [mutablePairs addObject:[pair URLEncodedStringValue]];
    }
 
    return [mutablePairs componentsJoinedByString:@"&"];
}
 

NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
    NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
 
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
    
    // 如果是字典,遍历后返回key[nestedKey]=nestedValue
    if ([value isKindOfClass:[NSDictionary class]]) {
        NSDictionary *dictionary = value;
        // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
        for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
            id nestedValue = dictionary[nestedKey];
            if (nestedValue) {
                [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
            }
        }
    } // 如果是数组,遍历后返回key[]=nestedValue
    else if ([value isKindOfClass:[NSArray class]]) {
        NSArray *array = value;
        for (id nestedValue in array) {
            [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
        }
    } // 如果是集合,遍历后返回key=obj
    else if ([value isKindOfClass:[NSSet class]]) {
        NSSet *set = value;
        for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
            [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
        }
    } // 其他返回key=value 
    else {
        [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
    }
 
    return mutableQueryStringComponents;
}

在使用AFHTTPRequestSerializer对HTTP请求的头部进行处理的时候,我们首要要调用(+) serializer初始化,然后设置属性的监听,这些属性在头文件里面都可以找到,实现文件里面也实现了set方法

self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }
 
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
    static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
    });
 
    return _AFHTTPRequestSerializerObservedKeyPaths;
}
通过KVO判断是否是新值,如果是的话,就加到mutableObservedChangedKeyPaths里面

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(__unused id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (context == AFHTTPRequestSerializerObserverContext) {
        if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
            [self.mutableObservedChangedKeyPaths removeObject:keyPath];
        } else {
            [self.mutableObservedChangedKeyPaths addObject:keyPath];
        }
    }
}

设置验证字段

- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
                                       password:(NSString *)password
{
    NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
    NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
    [self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
}

初始化之后,需要调用

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error
{
    // 断言                                     
    NSParameterAssert(method);
    NSParameterAssert(URLString);
    
    NSURL *url = [NSURL URLWithString:URLString];
 
    NSParameterAssert(url);
    // 根据url初始化request
    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    // 设置HTTP方法                                   
    mutableRequest.HTTPMethod = method;
    // 根据mutableObservedChangedKeyPaths存储的属性,设置到mutableRequest
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }
    // 调用- [requestBySerializingRequest:withParameters:error]方法
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
 
    return mutableRequest;
}
//===========================第五部分=============================

AFURLResponseSerialization
AFURLResponseSerialization是用来将返回的response处理成相应的格式,它通过协议对特定response的data进行解码。

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                           data:(nullable NSData *)data
                          error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
AFHTTPResponseSerializer可以通过+ serializer和- init方法进行初始化,实际上+ serializer内只是调用了- init

+ (instancetype)serializer {
    return [[self alloc] init];
}
 
- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }
    // 设置字符串编码类型,可接受的状态码,可接受的MIME类型
    self.stringEncoding = NSUTF8StringEncoding;
    self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
    self.acceptableContentTypes = nil;
 
    return self;
}
 acceptableStatusCodes和acceptableContentTypes可以通过外部设置

@property (nonatomic, copy, nullable) NSIndexSet *acceptableStatusCodes;
@property (nonatomic, copy, nullable) NSSet  *acceptableContentTypes;
然后可以调用- [validateResponse:data :error:]检查这个response是否包含可接受的状态码和可接受MIME类型来验证response的有效性,子类也可以增加特定域名检查,- [responseObjectForResponse:data:error]也是调用了这个方法,返回data

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    // 调用- [validateResponse:data:error:]方法,返回data 
    [self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
 
    return data;
}
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
                    data:(NSData *)data
                   error:(NSError * __autoreleasing *)error
{
    // 设置初始值
    BOOL responseIsValid = YES;
    NSError *validationError = nil;
 
    // 检查这个response是否包含可接受的状态码和可接受MIME类型
 
    if (error && !responseIsValid) {
        *error = validationError;
    }
    // 返回response是否有效性
    return responseIsValid;
}
 检查这个response是否包含可接受的状态码和可接受MIME类型

// 检查response是否为空,以及response是否是NSHTTPURLResponse类
    if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
        // acceptableContentTypes不为空并且response的MIME类型不在可接受的范围里
        if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) {
            
            // 包装错误信息
            if ([data length] > 0 && [response URL]) {
                NSMutableDictionary *mutableUserInfo = [@{
                                                          NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
                                                          NSURLErrorFailingURLErrorKey:[response URL],
                                                          AFNetworkingOperationFailingURLResponseErrorKey: response,
                                                        } mutableCopy];
                if (data) {
                    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
                }
 
                validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
            }
            
            responseIsValid = NO;
        }
        // acceptableStatusCodes不为空并且acceptableStatusCodes包含response的状态码,response的URL也存在
        if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
            // 包装错误信息
            NSMutableDictionary *mutableUserInfo = [@{
                                               NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
                                               NSURLErrorFailingURLErrorKey:[response URL],
                                               AFNetworkingOperationFailingURLResponseErrorKey: response,
                                       } mutableCopy];
 
            if (data) {
                mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
            }
 
            validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
 
            responseIsValid = NO;
        }
    }
 但是这里有个疑问,假如response为nil或者response不是NSHTTPURLResponse类,那下面的操作均不会对responseIsValid布尔值进行修改,最后返回的是个YES,但是这样的response不应该是NO么?

AFJSONResponseSerializer是继承于AFHTTPResponseSerializer

外部可以设置NSJSONReadingOptions和是否移除空值的key

@property (nonatomic, assign) NSJSONReadingOptions readingOptions;
@property (nonatomic, assign) BOOL removesKeysWithNullValues;
转换object的时候,会检查data是否是空格,这个是Safari的一个bug,具体请看Workaround for behavior of Rails to return a single space for head :ok (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }
 
    id responseObject = nil;
    NSError *serializationError = nil;
    // 判断是否是空格
    BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
    if (data.length > 0 && !isSpace) {
        responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
    } else {
        return nil;
    }
    // 调用AFJSONObjectByRemovingKeysWithNullValues把空值的key都移除掉,返回object
    if (self.removesKeysWithNullValues && responseObject) {
        responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
    }
 
    if (error) {
        *error = AFErrorWithUnderlyingError(serializationError, *error);
    }
 
    return responseObject;
}
AFXMLParserResponseSerializer则是直接校验response后,用data初始化NSXMLParser对象并返回

- (id)responseObjectForResponse:(NSHTTPURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }
 
    return [[NSXMLParser alloc] initWithData:data];
}
AFPropertyListResponseSerializer也是类似的处理

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }
 
    id responseObject;
    NSError *serializationError = nil;
 
    if (data) {
        responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
    }
 
    if (error) {
        *error = AFErrorWithUnderlyingError(serializationError, *error);
    }
 
    return responseObject;
}
AFImageResponseSerializer在验证response之后,会根据设置是否自动解压automaticallyInflatesResponseImage布尔值,来对imageData按图片比例返回UIImage对象

@property (nonatomic, assign) CGFloat imageScale;
@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage;
- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }
 
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
    // iOS需要手动解压图片
    if (self.automaticallyInflatesResponseImage) {
        return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
    } else {
        return AFImageWithDataAtScale(data, self.imageScale);
    }
#else
    // MacOS可以直接使用NSBitmapImageRep来解压
    NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
    NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
    [image addRepresentation:bitimage];
 
    return image;
#endif
 
    return nil;
}
 如果不解压的话,就直接根据imageData和scale来创建Image,但是这有个疑问是,AF为什么要创建两次image,我觉得可以直接使用- [imageWithData:scale:]方法

static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {
    UIImage *image = [UIImage af_safeImageWithData:data];
    if (image.images) {
        return image;
    }
    
    return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
}
但是如果用imageWithData转成UIImage对象后,由于网络图片PNG和JPG都是压缩格式,需要解压成bitmap后才能渲染到屏幕,这时会在主线程对图片进行解压操作,这是比较耗时的,可能还会对主线程造成阻塞,所以AF还提供了AFInflatedImageFromResponseWithDataAtScale方法,对PNG和JPG解压后,返回UIImage对象,这样避免了在主线程的解压操作,不会对主线程造成卡顿

static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) {
    if (!data || [data length] == 0) {
        return nil;
    }
    // 创建CGImageRef
    CGImageRef imageRef = NULL;
    // 用data创建CGDataProviderRef
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
 
    if ([response.MIMEType isEqualToString:@"image/png"]) {
        imageRef = CGImageCreateWithPNGDataProvider(dataProvider,  NULL, true, kCGRenderingIntentDefault);
    } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) {
        imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault);
 
        if (imageRef) {
            CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef);
            CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace);
 
            // 如果色彩空间是CMKY,CGImageCreateWithJPEGDataProvider是不会进行处理的,也就是不进行解压,将调用AFImageWithDataAtScale返回image
            if (imageColorSpaceModel == kCGColorSpaceModelCMYK) {
                CGImageRelease(imageRef);
                imageRef = NULL;
            }
        }
    }
 
    CGDataProviderRelease(dataProvider);
    // 不符合解压条件的,将调用AFImageWithDataAtScale返回image,但是这里如果符合解压条件的也会调用,以及下面会对超出大小的,直接返回image,这里我觉得应该统一对不符合条件的返回image,符合条件的就不需要调用AFImageWithDataAtScale
    UIImage *image = AFImageWithDataAtScale(data, scale);
    if (!imageRef) {
        if (image.images || !image) {
            return image;
        }
        // 这里调用CGImageCreateCopy,只会对图形本身结构进行拷贝,底层的数据是不会拷贝的
        imageRef = CGImageCreateCopy([image CGImage]);
        if (!imageRef) {
            return nil;
        }
    }
    // 设置图片的宽和高和存储一个像素所需要用到的字节
    size_t width = CGImageGetWidth(imageRef);
    size_t height = CGImageGetHeight(imageRef);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
    // 如果图片大小宽高乘积超过1024*1024或者bitsPerComponent大于8都不解压了,因为bitmap是一直存在UIImage对象里的,可能会把内存爆了
    if (width * height > 1024 * 1024 || bitsPerComponent > 8) {
        CGImageRelease(imageRef);
 
        return image;
    }
 
    // 画布参数
    size_t bytesPerRow = 0;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
 
    if (colorSpaceModel == kCGColorSpaceModelRGB) {
        uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wassign-enum"
        if (alpha == kCGImageAlphaNone) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaNoneSkipFirst;
        } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) {
            bitmapInfo &= ~kCGBitmapAlphaInfoMask;
            bitmapInfo |= kCGImageAlphaPremultipliedFirst;
        }
#pragma clang diagnostic pop
    }
    // 创建画布
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
 
    CGColorSpaceRelease(colorSpace);
 
    if (!context) {
        CGImageRelease(imageRef);
 
        return image;
    }
    // 在画布上画出图片
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef);
    // 保存成CGImageRef
    CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context);
 
    CGContextRelease(context);
    // 再转成UIImage对象
    UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation];
 
    CGImageRelease(inflatedImageRef);
    CGImageRelease(imageRef);
 
    return inflatedImage;
}
AFCompoundResponseSerializer

- (id)responseObjectForResponse:(NSURLResponse *)response
                           data:(NSData *)data
                          error:(NSError *__autoreleasing *)error
{
    // 遍历responseSerializers                    
    for (id  serializer in self.responseSerializers) {
        // 如果serializer不是AFHTTPResponseSerializer类,则继续
        if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) {
            continue;
        }
 
        NSError *serializerError = nil;
        // 一层一层的调用自己的- [responseObjectForResponse:data:error:],直到返回responseObject
        id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError];
        if (responseObject) {
            if (error) {
                *error = AFErrorWithUnderlyingError(serializerError, *error);
            }
 
            return responseObject;
        }
    }
 
    return [super responseObjectForResponse:response data:data error:error];
}

你可能感兴趣的:(AFNetworking源码解析)