iOS DeveloperiOS && AndroidiOS程序猿

AFNetworking 源码阅读(v3.2.1)

2018-07-04  本文已影响75人  cdcyd

AFNetworking项目地址 https://github.com/AFNetworking/AFNetworking
下载打开后目录

AFNetworking
1.AFNetworking文件下是实现HTTP请求的类
2.UIKit+AFNetworking文件下是实现图片下载的类

下面我们主要看AFNetworking的HTTP请求实现,我们使用AF发送一个请求很简单,如下面的一个GET请求的例子

// 请求管理器
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 参数JSON格式
manager.requestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:NSJSONWritingPrettyPrinted];
// 返回JSON格式
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
// 超时时间
manager.requestSerializer.timeoutInterval = 30;
// 最大线程数
manager.operationQueue.maxConcurrentOperationCount = 5;
// 开始发送请求
[manager GET:@"url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    // 请求成功
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    // 请求失败
}];

上面涉及到了AFHTTPSessionManagerAFJSONRequestSerializerAFJSONResponseSerializer几个类,下面我们就来挨个看他们都是干什么的

@interface AFHTTPRequestSerializer : NSObject <AFURLRequestSerialization>

/// 返回参数编码的编码样式,默认为 NSUTF8StringEncoding
@property (nonatomic, assign) NSStringEncoding stringEncoding;

/// 是否可以通过手机网络发送请求
@property (nonatomic, assign) BOOL allowsCellularAccess;

/// 缓存策略
@property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy;

/// 是否对cookies进行默认处理  默认为YES
@property (nonatomic, assign) BOOL HTTPShouldHandleCookies;

/// 是否可以在上个数据传输的请求完成后继续传输数据 默认为No
@property (nonatomic, assign) BOOL HTTPShouldUsePipelining;

/// 服务器的类型 默认为NSURLNetworkServiceTypeDefault
@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;

/// 一个请求的超时时长 默认为60s
@property (nonatomic, assign) NSTimeInterval timeoutInterval;

/// 请求头的信息, 默认包含 Accept-Language 和 User-Agent
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;

/// 返回一个默认配置序列化对象
+ (instancetype)serializer;

/// 设置Header里面的字段,如果为field为空,那么这个字段会从Header里面移除
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;

/// 根据key取出Hearder里面的值,返回字符串或者nil
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;

/// 设置HTTP认证的用户名和密码
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username password:(NSString *)password;

/// 移除验证的用户名和密码
- (void)clearAuthorizationHeader;

/// 将参数编码成一个查询字符串(默认包含:GET、DELETE、HEAD)
@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;

/// 根据之前预定义的style设置查询字符串序列化的方法
- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style;

/// 根据指定的block设置一个自定义查询字符序列化的方法。Block中传入一个request,编码的参数parameters和一个error,返回请求参数编码成一个查询字符串
- (void)setQueryStringSerializationWithBlock:(nullable NSString * (^)(NSURLRequest *request, id parameters, NSError * __autoreleasing *error))block;

/// 创建一个请求,根据传入的Method,如果为 `GET`、`HEAD`、`DELETE`,参数会拼接在Url的后面,否则参数会设置成HTTP的请求体,并根据request指定的parameterEncoding参数编码
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(nullable id)parameters
                                     error:(NSError * _Nullable __autoreleasing *)error;

/// 通过`AFMultipartFormData`类型的formData来构建请求体
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
                                              URLString:(NSString *)URLString
                                             parameters:(nullable NSDictionary <NSString *, id> *)parameters
                              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                                                  error:(NSError * _Nullable __autoreleasing *)error;

/// 通过request创建一个request,新request的httpBody是`fileURL`指定的文件,并且是通过`HTTPBodyStream`这个属性添加,`HTTPBodyStream`属性的数据会自动添加为httpBody
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
                             writingStreamContentsToFile:(NSURL *)fileURL
                                       completionHandler:(nullable void (^)(NSError * _Nullable error))handler;

@end

总结一下AFHTTPRequestSerializer,就是封装请求头信息,序列化请求参数
HTTP的头信息包括:请求方式、请求的URL 、HTTP的版本、Host、 Accept、 Cookie、 User-Agent、Accept-Language、Accept-Encoding、Connection等,其中有很多就是AF帮助我们构建的,下面贴出AFHTTPRequestSerializer的初始化方法

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    // 编码方式
    self.stringEncoding = NSUTF8StringEncoding;

    // 存储HTTP头信息
    self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];

    // 修改头信息的线程
    self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);

    // 构建Accept-Language信息
    NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
    [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        float q = 1.0f - (idx * 0.1f);
        [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
        *stop = q <= 0.5f;
    }];
    [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];

    // 构建User-Agent信息(源码这里分类iOS、Watch、MAC三中,这里简化为iOS)
    NSString *userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
    if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
        NSMutableString *mutableUserAgent = [userAgent mutableCopy];
        if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
            userAgent = mutableUserAgent;
        }
    }
    [self setValue:userAgent forHTTPHeaderField:@"User-Agent"];

    // 需要转换为查询字符串参数的请求类型 默认 "GET" "HEAD" "DELETE"
    self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];

    // 添加一些属性的KVC,包括allowsCellularAccess、cachePolicy、HTTPShouldHandleCookies、HTTPShouldUsePipelining、networkServiceType、timeoutInterval
    self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }

    return self;
}

构建请求对象的方法有3个,如下截图


构建请求发放申明

下面贴出第一个方法的具体实现

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters error:(NSError *__autoreleasing *)error
{
    NSParameterAssert(method);
    NSParameterAssert(URLString);

    // 基础url
    NSURL *url = [NSURL URLWithString:URLString];

    NSParameterAssert(url);

    // 请求对象
    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    mutableRequest.HTTPMethod = method;

    // 设置请求参数
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    // AFURLRequestSerialization协议的方法,用于序列化参数,添加一些header信息
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

    return mutableRequest;
}

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error
{
    NSParameterAssert(request);

    // 深拷贝一份请求对象
    NSMutableURLRequest *mutableRequest = [request mutableCopy];

    // 设置header信息
    [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
        if (![request valueForHTTPHeaderField:field]) {
            [mutableRequest setValue:value forHTTPHeaderField:field];
        }
    }];

    // 参数序列化
    NSString *query = nil;
    if (parameters) {
        if (self.queryStringSerialization) {
            NSError *serializationError;
            query = self.queryStringSerialization(request, parameters, &serializationError);

            if (serializationError) {
                if (error) {
                    *error = serializationError;
                }

                return nil;
            }
        } else {
            switch (self.queryStringSerializationStyle) {
                case AFHTTPRequestQueryStringDefaultStyle:
                    query = AFQueryStringFromParameters(parameters);
                    break;
            }
        }
    }

    if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
        // 将参数转换为查询字符串并拼接到url后面,默认"GET" "HEAD" "DELETE"请求会走这里
        if (query && query.length > 0) {
            mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
        }
    } else {
        // 其它请求将参数设置成HTTPBody,并且如果没有参数,则设置成""
        if (!query) {
            query = @"";
        }
        if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
            [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        }
        [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
    }

    return mutableRequest;
}

到此,我们就构建NSURLRequest,其实它主要有两部分:构建头信息、处理参数

下面我们再来看一下返回信息AFJSONResponseSerializer

它们都遵循AFURLResponseSerialization协议,下面贴出AFJSONResponseSerializer的实现方法

// AFURLResponseSerialization协议
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error
{
    // 判断返回的数据是否合法,如果不合法,直接返回nil
    if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
        if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
            return nil;
        }
    }

    // json解析
    BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
    if (data.length == 0 || isSpace) {
        return nil;
    }
    NSError *serializationError = nil;
    id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
    if (!responseObject)
    {
        // 解析失败,返回nil
        if (error) {
            *error = AFErrorWithUnderlyingError(serializationError, *error);
        }
        return nil;
    }

    // 是否需要移除nil值的key
    if (self.removesKeysWithNullValues) {
        return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
    }
    return responseObject;
}

// 验证数据合法性函数
- (BOOL)validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error
{
    // 是否合法
    BOOL responseIsValid = YES;
    // 错误信息
    NSError *validationError = nil;
    // 验证并生成错误信息
    if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
        if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] && !([response MIMEType] == nil && [data length] == 0)) {
            if ([data length] > 0 && [response URL]) {
                NSString *desc = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]];
                NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey:desc,
                                                          NSURLErrorFailingURLErrorKey:[response URL],
                                                          AFNetworkingOperationFailingURLResponseErrorKey: response} mutableCopy];
                if (data) {
                    mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
                }
                validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
            }
            responseIsValid = NO;
        }

        if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
            NSString *desc = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode];
            NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: desc,
                                                      NSURLErrorFailingURLErrorKey:[response URL],
                                                      AFNetworkingOperationFailingURLResponseErrorKey: response} mutableCopy];
            if (data) {
                mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
            }
            validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
            responseIsValid = NO;
        }
    }
    if (error && !responseIsValid) {
        *error = validationError;
    }
    return responseIsValid;
}

总结AFHTTPResponseSerializer及其子类,是处理NSURLResponse的,主要处理错误码、错误信息、解析返回的NSData等

@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>

// 基础url
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;

// 请求x实体
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;

// 返回实体
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;

// SSL证书验证
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

// 实例
+ (instancetype)manager;

// 通过url创建实例
- (instancetype)initWithBaseURL:(nullable NSURL *)url;

// 通过url和config创建实例
- (instancetype)initWithBaseURL:(nullable NSURL *)url
           sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

// 发起get请求
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(nullable id)parameters
                      success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                      failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;


// 发起get请求,带进度条
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
                            parameters:(nullable id)parameters
                              progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
                               success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                               failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起head请求
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
                    parameters:(nullable id)parameters
                       success:(nullable void (^)(NSURLSessionDataTask *task))success
                       failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起post请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(nullable id)parameters
                       success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                       failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;

// 发起post请求,带进度条
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
                               progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起post请求,添加formdata,一般用于上传文件
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(nullable id)parameters
     constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                       success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                       failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;

// 发起post请求,添加formdata,一般用于上传文件,带进度条
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                               progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起put请求
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
                   parameters:(nullable id)parameters
                      success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                      failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起patch请求
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
                     parameters:(nullable id)parameters
                        success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                        failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

// 发起delete请求
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
                      parameters:(nullable id)parameters
                         success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                         failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

@end

它的实现最后都会汇集到下面两个方法中,一个上传,一个下载

- (NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
     constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
                      progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
                       success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                       failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
    // 构建请求实体
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

        return nil;
    }

    // 构建上传任务
    __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(task, error);
            }
        } else {
            if (success) {
                success(task, responseObject);
            }
        }
    }];

    // 开始任务
    [task resume];

    return task;
}
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    // 构建请求体
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    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;
}

从上面的方法中,我们可以看出都分为3步,构建请求体、构建下载/上传任务、开始任务
构建请求体:它由AFHTTPRequestSerializer完成
构建下载/上传任务:它主要由AFURLSessionManager完成
下面我们就来看一下AFURLSessionManager

@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>

// 会话
@property (readonly, nonatomic, strong) NSURLSession *session;

// NSURLSession的队列
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

// 序列化响应数据的对象
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;

// 安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

#if !TARGET_OS_WATCH
// 网络监控管理者
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
#endif

// 当前被管理的任务的集合(包括data upload download)
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

// 当前data的任务集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

// 当前upload的任务集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

// 当前download的任务集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

// 回调的队列,如果为空,就在主队列
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

// block会在这个组中调用,如果为空,就使用一个私有的
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

// 解决在后台创建上传任务返回nil的bug,默认为NO,如果设为YES,在后台创建上传任务失败会尝试重新创建该任务
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;

// 初始化
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

// 是否取消未完成的任务来使session失效
// NSURLSession有两个方法:
// -(void)finishTasksAndInvalidate; 标示待完成所有的任务后失效
// -(void)invalidateAndCancel; 标示 立即失效,未完成的任务也将结束
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

// 下面2个是DataTask相关的方法,对应没有进度条和有进度条
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;
- (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;

/// 下面3个是UploadTask相关的方法,对应fileURL/data/request 这三种不同的数据源
- (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;
- (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;
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

// 下面2个是DownloadTask相关的方法
- (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;
- (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;

// 通过task获取其上传进度
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;

// 通过ytask获取其下载进度
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

// 下面是一些代理和block回调的相关函数
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;

- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;

- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * _Nullable (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block;

- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;

- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;

- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;

- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block;

- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block;

- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;

- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block;

- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block AF_API_UNAVAILABLE(macos);

- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable  (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;

- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;

- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;

@end

从上可以知道,任务的创建有3种data(数据)、upload(上传)、download(下载),它们的实现都很相似,这里从data来分析,下面是构建NSURLSessionDataTask的实现代码

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

    __block NSURLSessionDataTask *dataTask = nil;
    url_session_manager_create_task_safely(^{
        // 通过NSURLSession创建NSURLSessionDataTask
        // - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
        // - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
        // - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL;
        // - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData;
        // - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
        // - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
        // - (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
        // - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;
        // - (NSURLSessionStreamTask *)streamTaskWithHostName:(NSString *)hostname port:(NSInteger)port
        // - (NSURLSessionStreamTask *)streamTaskWithNetService:(NSNetService *)service
        dataTask = [self.session dataTaskWithRequest:request];
    });

    // 添加AFURLSessionManagerTaskDelegate代理
    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

上面的代码很简单,就是根据方法调用NSURLSession的相关方法创建相关的任务(data、upload、download)等,在添加AFURLSessionManagerTaskDelegate代理
第一步很好理解,就是创建任务,为什么要有第二步呢?为什么还有添加一个代理呢?
首先我们来看一下NSURLSession的代理,它有4个代理,在创建时只要设置一个相当于4个都设置了

self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration 
                                             delegate:self 
                                             delegateQueue:self.operationQueue];

这里设置的代理后,就相对于设置了下面4个代理

1.NSURLSessionDelegate
URLSession:didBecomeInvalidWithError:
URLSession:didReceiveChallenge:completionHandler:
URLSessionDidFinishEventsForBackgroundURLSession:

2. NSURLSessionTaskDelegate
URLSession:willPerformHTTPRedirection:newRequest:completionHandler:
URLSession:task:didReceiveChallenge:completionHandler:
URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
URLSession:task:needNewBodyStream:
URLSession:task:didCompleteWithError:

3. NSURLSessionDataDelegate
URLSession:dataTask:didReceiveResponse:completionHandler:
URLSession:dataTask:didBecomeDownloadTask:
URLSession:dataTask:didReceiveData:
URLSession:dataTask:willCacheResponse:completionHandler:

4. NSURLSessionDownloadDelegate
URLSession:downloadTask:didFinishDownloadingToURL:
URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:
URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:

这里需要注意的是,这4个代理不一定都会走,它会根据Task的类型走,如DataTask才会走NSURLSessionDataDelegate,这里还有一个问题,就是当有多个任务同时进行时,我们不好区分到底是哪个人物的回调,当然我们可以通过比较dataTask,AFURLSessionManagerTaskDelegate代理就是为了解决这个问题的,我们就用DataTask类型来举例

- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
              downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
             completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    // 创建代理
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
    delegate.manager = self;
    // 设置完成回调block
    delegate.completionHandler = completionHandler;
    // 任务描述
    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    // 存储task和delegate
    [self setDelegate:delegate forTask:dataTask];
    // 任务上传进度block
    delegate.uploadProgressBlock = uploadProgressBlock;
    // 任务下载进度block
    delegate.downloadProgressBlock = downloadProgressBlock;
}

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

上面代码就是为每个task创建了一个代理,并且将完成、上传进度、下载进度的回调block赋值个代理,再将代理和任务存储到属性mutableTaskDelegatesKeyedByTaskIdentifier中,这样就使得每一个task都有它自己的代理,当task回调时,我们通过它找到delegate,再用delegate调用相关代理方法,然后再在代理方法中回调相关的block,具体实现如下
在NSURLSessionDataDelegate回调时,下面是获取数据完成的代理

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    // 获取任务对应的delegate
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // 如果有delegate,则调用相关的代理方法
    if (delegate) {
        [delegate URLSession:session task:task didCompleteWithError:error];
        // 这里任务完成了,移除任务和代理
        [self removeDelegateForTask:task];
    }
    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }
}

再来看AFURLSessionManagerTaskDelegate代理中相关实现

- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    __strong AFURLSessionManager *manager = self.manager;
    __block id responseObject = nil;
    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];
        self.mutableData = nil;
    }

    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }

    if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }
            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }
            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
}

这样就实现每一个任务都有它自己单独的代理,完成后即进行回调,还有一个好处是,当任务完成时,就可以移除代理,这样可以打破block的循环引用,所以我们再AF的block中直接在self不会造成循环引用

下面在看一下SSL相关类AFSecurityPolicy

@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>

// 返回SSL Pinning的类型
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;

// 这个属性保存着所有的可用做校验的证书的集合
// AFNetworking默认会搜索工程中所有.cer的证书文件
// 如果想制定某些证书,可使用certificatesInBundle在目标路径下加载证书,然后调用policyWithPinningMode:withPinnedCertificates创建一个本类对象。
// 只要在证书集合中任何一个校验通过,evaluateServerTrust:forDomain: 就会返回true,即通过校验
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;

// 允许无效或过期的证书,默认是不允许
@property (nonatomic, assign) BOOL allowInvalidCertificates;

// 是否验证证书中的域名domain
@property (nonatomic, assign) BOOL validatesDomainName;

// 返回指定bundle中的证书
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;

// 默认的实例对象,默认的认证设置为:
// 1. 不允许无效或过期的证书
// 2. 验证domain名称
// 3. 不对证书和公钥进行验证
+ (instancetype)defaultPolicy;

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;

+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
                  forDomain:(nullable NSString *)domain;

@end

下面函数是用来保证任务创建安全的,AF给出的解释是在iOS8.0以前,任务创建有线程安全问题,如果你适配8.0以后的话,就不会用它了

static dispatch_queue_t url_session_manager_creation_queue() {
    static dispatch_queue_t af_url_session_manager_creation_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL);
    });

    return af_url_session_manager_creation_queue;
}

static void url_session_manager_create_task_safely(dispatch_block_t _Nonnull block) {
    if (block != NULL) {
        if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
            // Fix of bug
            // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
            // Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
            dispatch_sync(url_session_manager_creation_queue(), block);
        } else {
            block();
        }
    }
}

下面是处理代理回调的线程函数,它是并行队列,在多个回调同时触发时,可以同时处理,可以加快数据的处理速度

static dispatch_queue_t url_session_manager_processing_queue() {
    static dispatch_queue_t af_url_session_manager_processing_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT);
    });
    return af_url_session_manager_processing_queue;
}

下面是完成时的回调队列,当completionGroup属性为nil时,默认就使用它

static dispatch_group_t url_session_manager_completion_group() {
    static dispatch_group_t af_url_session_manager_completion_group;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        af_url_session_manager_completion_group = dispatch_group_create();
    });
    return af_url_session_manager_completion_group;
}

下面再贴出完成时回调的代码

if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
        // 请求出错
        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                // 在completionQueue存在时,则completionQueue中回调,否则在主队列中回调
                self.completionHandler(task.response, responseObject, error);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                // 在主线程中发出任务完成通知
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {
        // 请求成功
        dispatch_async(url_session_manager_processing_queue(), ^{
            // 子线程并行处理回调数据
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }
            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }
            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                // 处理完成后,在completionQueue存在时,则completionQueue中回调,否则在主队列中回调
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    // 在主线程中发出任务完成通知
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }

从上面代码可以看出,在默认情况下,不论我们在哪个线程用AF做请求,它的回调永远是在主队列中

到此AFNetworking文件下的类就全部读完了,实际我读AF就是想了解,在请求时,AF到底都为我们做了什么,总结一下:

  1. 请求体NSURLRequest的封装,涉及到构建head信息、Request相关参数设置,请求参数序列化等
  2. 根据请求类型创建相关的任务NSURLSessionTask,涉及到任务回调,线程安全等
  3. 返回数据NSData的解析
  4. HTTPS的支持

这里只是简单的总结这4步,但是每一步的实现都不易,如果想深入了解的话还会涉及到更多的知识点,同时也体会到写一个优秀的网络框架实属不易!

上一篇下一篇

猜你喜欢

热点阅读