AFNetworking項(xiàng)目地址 https://github.com/AFNetworking/AFNetworking
下載打開后目錄

1.AFNetworking文件下是實(shí)現(xiàn)HTTP請(qǐng)求的類
2.UIKit+AFNetworking文件下是實(shí)現(xiàn)圖片下載的類
下面我們主要看AFNetworking的HTTP請(qǐng)求實(shí)現(xiàn),我們使用AF發(fā)送一個(gè)請(qǐng)求很簡(jiǎn)單,如下面的一個(gè)GET請(qǐng)求的例子
// 請(qǐng)求管理器
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// 參數(shù)JSON格式
manager.requestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:NSJSONWritingPrettyPrinted];
// 返回JSON格式
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
// 超時(shí)時(shí)間
manager.requestSerializer.timeoutInterval = 30;
// 最大線程數(shù)
manager.operationQueue.maxConcurrentOperationCount = 5;
// 開始發(fā)送請(qǐng)求
[manager GET:@"url" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// 請(qǐng)求成功
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 請(qǐng)求失敗
}];
上面涉及到了AFHTTPSessionManager、AFJSONRequestSerializer、AFJSONResponseSerializer幾個(gè)類,下面我們就來(lái)挨個(gè)看他們都是干什么的
- AFJSONRequestSerializer:請(qǐng)求參數(shù)按JSON格式序列化,還有一個(gè)AFPropertyListRequestSerializer:請(qǐng)求參數(shù)按Plist格式序列化,它們都繼承自AFHTTPRequestSerializer,而AFHTTPRequestSerializer的參數(shù)序列化格式是默認(rèn)的普通的http的編碼格式,即url?key1=value1&key2=value2,下面我們就來(lái)看一下AFHTTPRequestSerializer
@interface AFHTTPRequestSerializer : NSObject <AFURLRequestSerialization>
/// 返回參數(shù)編碼的編碼樣式,默認(rèn)為 NSUTF8StringEncoding
@property (nonatomic, assign) NSStringEncoding stringEncoding;
/// 是否可以通過(guò)手機(jī)網(wǎng)絡(luò)發(fā)送請(qǐng)求
@property (nonatomic, assign) BOOL allowsCellularAccess;
/// 緩存策略
@property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy;
/// 是否對(duì)cookies進(jìn)行默認(rèn)處理 默認(rèn)為YES
@property (nonatomic, assign) BOOL HTTPShouldHandleCookies;
/// 是否可以在上個(gè)數(shù)據(jù)傳輸?shù)恼?qǐng)求完成后繼續(xù)傳輸數(shù)據(jù) 默認(rèn)為No
@property (nonatomic, assign) BOOL HTTPShouldUsePipelining;
/// 服務(wù)器的類型 默認(rèn)為NSURLNetworkServiceTypeDefault
@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;
/// 一個(gè)請(qǐng)求的超時(shí)時(shí)長(zhǎng) 默認(rèn)為60s
@property (nonatomic, assign) NSTimeInterval timeoutInterval;
/// 請(qǐng)求頭的信息, 默認(rèn)包含 Accept-Language 和 User-Agent
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
/// 返回一個(gè)默認(rèn)配置序列化對(duì)象
+ (instancetype)serializer;
/// 設(shè)置Header里面的字段,如果為field為空,那么這個(gè)字段會(huì)從Header里面移除
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;
/// 根據(jù)key取出Hearder里面的值,返回字符串或者nil
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;
/// 設(shè)置HTTP認(rèn)證的用戶名和密碼
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username password:(NSString *)password;
/// 移除驗(yàn)證的用戶名和密碼
- (void)clearAuthorizationHeader;
/// 將參數(shù)編碼成一個(gè)查詢字符串(默認(rèn)包含:GET、DELETE、HEAD)
@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;
/// 根據(jù)之前預(yù)定義的style設(shè)置查詢字符串序列化的方法
- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style;
/// 根據(jù)指定的block設(shè)置一個(gè)自定義查詢字符序列化的方法。Block中傳入一個(gè)request,編碼的參數(shù)parameters和一個(gè)error,返回請(qǐng)求參數(shù)編碼成一個(gè)查詢字符串
- (void)setQueryStringSerializationWithBlock:(nullable NSString * (^)(NSURLRequest *request, id parameters, NSError * __autoreleasing *error))block;
/// 創(chuàng)建一個(gè)請(qǐng)求,根據(jù)傳入的Method,如果為 `GET`、`HEAD`、`DELETE`,參數(shù)會(huì)拼接在Url的后面,否則參數(shù)會(huì)設(shè)置成HTTP的請(qǐng)求體,并根據(jù)request指定的parameterEncoding參數(shù)編碼
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
error:(NSError * _Nullable __autoreleasing *)error;
/// 通過(guò)`AFMultipartFormData`類型的formData來(lái)構(gòu)建請(qǐng)求體
- (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;
/// 通過(guò)request創(chuàng)建一個(gè)request,新request的httpBody是`fileURL`指定的文件,并且是通過(guò)`HTTPBodyStream`這個(gè)屬性添加,`HTTPBodyStream`屬性的數(shù)據(jù)會(huì)自動(dòng)添加為httpBody
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
writingStreamContentsToFile:(NSURL *)fileURL
completionHandler:(nullable void (^)(NSError * _Nullable error))handler;
@end
總結(jié)一下AFHTTPRequestSerializer,就是封裝請(qǐng)求頭信息,序列化請(qǐng)求參數(shù)
HTTP的頭信息包括:請(qǐng)求方式、請(qǐng)求的URL 、HTTP的版本、Host、 Accept、 Cookie、 User-Agent、Accept-Language、Accept-Encoding、Connection等,其中有很多就是AF幫助我們構(gòu)建的,下面貼出AFHTTPRequestSerializer的初始化方法
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
// 編碼方式
self.stringEncoding = NSUTF8StringEncoding;
// 存儲(chǔ)HTTP頭信息
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
// 修改頭信息的線程
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
// 構(gòu)建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"];
// 構(gòu)建User-Agent信息(源碼這里分類iOS、Watch、MAC三中,這里簡(jiǎn)化為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"];
// 需要轉(zhuǎn)換為查詢字符串參數(shù)的請(qǐng)求類型 默認(rèn) "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;
}
構(gòu)建請(qǐng)求對(duì)象的方法有3個(gè),如下截圖

下面貼出第一個(gè)方法的具體實(shí)現(xiàn)
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method URLString:(NSString *)URLString parameters:(id)parameters error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
// 基礎(chǔ)url
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
// 請(qǐng)求對(duì)象
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
// 設(shè)置請(qǐng)求參數(shù)
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
// AFURLRequestSerialization協(xié)議的方法,用于序列化參數(shù),添加一些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);
// 深拷貝一份請(qǐng)求對(duì)象
NSMutableURLRequest *mutableRequest = [request mutableCopy];
// 設(shè)置header信息
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
// 參數(shù)序列化
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]]) {
// 將參數(shù)轉(zhuǎn)換為查詢字符串并拼接到url后面,默認(rèn)"GET" "HEAD" "DELETE"請(qǐng)求會(huì)走這里
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
} else {
// 其它請(qǐng)求將參數(shù)設(shè)置成HTTPBody,并且如果沒有參數(shù),則設(shè)置成""
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;
}
到此,我們就構(gòu)建NSURLRequest,其實(shí)它主要有兩部分:構(gòu)建頭信息、處理參數(shù)
下面我們?cè)賮?lái)看一下返回信息AFJSONResponseSerializer
- AFJSONResponseSerializer:它主要用于對(duì)返回二進(jìn)制數(shù)據(jù)NSData的解析,繼承自AFHTTPResponseSerializer,其中的JSON表示它能解析的類型
- AFHTTPResponseSerializer:不做處理,直接返回NSData
- AFJSONResponseSerializer:JSON
- AFXMLParserResponseSerializer:xml
- AFXMLDocumentResponseSerializer:(Mac OS X) iPhone不能直接使用,需要用GData-XML
- AFPropertyListResponseSerializer:plist
- AFImageResponseSerializer:image
- AFCompoundResponseSerializer:多個(gè)組合,初始化時(shí)需要傳入上面的一種或幾種類型
它們都遵循AFURLResponseSerialization協(xié)議,下面貼出AFJSONResponseSerializer的實(shí)現(xiàn)方法
// AFURLResponseSerialization協(xié)議
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error
{
// 判斷返回的數(shù)據(jù)是否合法,如果不合法,直接返回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;
}
// 驗(yàn)證數(shù)據(jù)合法性函數(shù)
- (BOOL)validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error
{
// 是否合法
BOOL responseIsValid = YES;
// 錯(cuò)誤信息
NSError *validationError = nil;
// 驗(yàn)證并生成錯(cuò)誤信息
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;
}
總結(jié)AFHTTPResponseSerializer及其子類,是處理NSURLResponse的,主要處理錯(cuò)誤碼、錯(cuò)誤信息、解析返回的NSData等
- AFHTTPSessionManager:請(qǐng)求管理類,它繼承自AFURLSessionManager,它主要封裝了GET,POST,PUT,DELETE等等HTTPMehtod
@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
// 基礎(chǔ)url
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
// 請(qǐng)求x實(shí)體
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
// 返回實(shí)體
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
// SSL證書驗(yàn)證
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
// 實(shí)例
+ (instancetype)manager;
// 通過(guò)url創(chuàng)建實(shí)例
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
// 通過(guò)url和config創(chuàng)建實(shí)例
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// 發(fā)起get請(qǐng)求
- (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;
// 發(fā)起get請(qǐng)求,帶進(jìn)度條
- (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;
// 發(fā)起head請(qǐng)求
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// 發(fā)起post請(qǐng)求
- (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;
// 發(fā)起post請(qǐng)求,帶進(jìn)度條
- (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;
// 發(fā)起post請(qǐng)求,添加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;
// 發(fā)起post請(qǐng)求,添加formdata,一般用于上傳文件,帶進(jìn)度條
- (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;
// 發(fā)起put請(qǐng)求
- (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;
// 發(fā)起patch請(qǐng)求
- (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;
// 發(fā)起delete請(qǐng)求
- (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
它的實(shí)現(xiàn)最后都會(huì)匯集到下面兩個(gè)方法中,一個(gè)上傳,一個(gè)下載
- (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
{
// 構(gòu)建請(qǐng)求實(shí)體
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;
}
// 構(gòu)建上傳任務(wù)
__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);
}
}
}];
// 開始任務(wù)
[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
{
// 構(gòu)建請(qǐng)求體
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;
}
// 構(gòu)建下載任務(wù)
__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步,構(gòu)建請(qǐng)求體、構(gòu)建下載/上傳任務(wù)、開始任務(wù)
構(gòu)建請(qǐng)求體:它由AFHTTPRequestSerializer完成
構(gòu)建下載/上傳任務(wù):它主要由AFURLSessionManager完成
下面我們就來(lái)看一下AFURLSessionManager
- AFURLSessionManager:管理NSURLSession對(duì)象,下面是它的頭文件注釋
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
// 會(huì)話
@property (readonly, nonatomic, strong) NSURLSession *session;
// NSURLSession的隊(duì)列
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
// 序列化響應(yīng)數(shù)據(jù)的對(duì)象
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
// 安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
#if !TARGET_OS_WATCH
// 網(wǎng)絡(luò)監(jiān)控管理者
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
#endif
// 當(dāng)前被管理的任務(wù)的集合(包括data upload download)
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
// 當(dāng)前data的任務(wù)集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
// 當(dāng)前upload的任務(wù)集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
// 當(dāng)前download的任務(wù)集合
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
// 回調(diào)的隊(duì)列,如果為空,就在主隊(duì)列
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
// block會(huì)在這個(gè)組中調(diào)用,如果為空,就使用一個(gè)私有的
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
// 解決在后臺(tái)創(chuàng)建上傳任務(wù)返回nil的bug,默認(rèn)為NO,如果設(shè)為YES,在后臺(tái)創(chuàng)建上傳任務(wù)失敗會(huì)嘗試重新創(chuàng)建該任務(wù)
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;
// 初始化
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// 是否取消未完成的任務(wù)來(lái)使session失效
// NSURLSession有兩個(gè)方法:
// -(void)finishTasksAndInvalidate; 標(biāo)示待完成所有的任務(wù)后失效
// -(void)invalidateAndCancel; 標(biāo)示 立即失效,未完成的任務(wù)也將結(jié)束
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;
// 下面2個(gè)是DataTask相關(guān)的方法,對(duì)應(yīng)沒有進(jìn)度條和有進(jìn)度條
- (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個(gè)是UploadTask相關(guān)的方法,對(duì)應(yīng)fileURL/data/request 這三種不同的數(shù)據(jù)源
- (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個(gè)是DownloadTask相關(guān)的方法
- (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;
// 通過(guò)task獲取其上傳進(jìn)度
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
// 通過(guò)ytask獲取其下載進(jìn)度
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
// 下面是一些代理和block回調(diào)的相關(guān)函數(shù)
- (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
從上可以知道,任務(wù)的創(chuàng)建有3種data(數(shù)據(jù))、upload(上傳)、download(下載),它們的實(shí)現(xiàn)都很相似,這里從data來(lái)分析,下面是構(gòu)建NSURLSessionDataTask的實(shí)現(xiàn)代碼
- (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(^{
// 通過(guò)NSURLSession創(chuàng)建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;
}
上面的代碼很簡(jiǎn)單,就是根據(jù)方法調(diào)用NSURLSession的相關(guān)方法創(chuàng)建相關(guān)的任務(wù)(data、upload、download)等,在添加AFURLSessionManagerTaskDelegate代理
第一步很好理解,就是創(chuàng)建任務(wù),為什么要有第二步呢?為什么還有添加一個(gè)代理呢?
首先我們來(lái)看一下NSURLSession的代理,它有4個(gè)代理,在創(chuàng)建時(shí)只要設(shè)置一個(gè)相當(dāng)于4個(gè)都設(shè)置了
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration
delegate:self
delegateQueue:self.operationQueue];
這里設(shè)置的代理后,就相對(duì)于設(shè)置了下面4個(gè)代理
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個(gè)代理不一定都會(huì)走,它會(huì)根據(jù)Task的類型走,如DataTask才會(huì)走NSURLSessionDataDelegate,這里還有一個(gè)問(wèn)題,就是當(dāng)有多個(gè)任務(wù)同時(shí)進(jìn)行時(shí),我們不好區(qū)分到底是哪個(gè)人物的回調(diào),當(dāng)然我們可以通過(guò)比較dataTask,AFURLSessionManagerTaskDelegate代理就是為了解決這個(gè)問(wèn)題的,我們就用DataTask類型來(lái)舉例
- (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
{
// 創(chuàng)建代理
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
// 設(shè)置完成回調(diào)block
delegate.completionHandler = completionHandler;
// 任務(wù)描述
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
// 存儲(chǔ)task和delegate
[self setDelegate:delegate forTask:dataTask];
// 任務(wù)上傳進(jìn)度block
delegate.uploadProgressBlock = uploadProgressBlock;
// 任務(wù)下載進(jìn)度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];
}
上面代碼就是為每個(gè)task創(chuàng)建了一個(gè)代理,并且將完成、上傳進(jìn)度、下載進(jìn)度的回調(diào)block賦值個(gè)代理,再將代理和任務(wù)存儲(chǔ)到屬性mutableTaskDelegatesKeyedByTaskIdentifier中,這樣就使得每一個(gè)task都有它自己的代理,當(dāng)task回調(diào)時(shí),我們通過(guò)它找到delegate,再用delegate調(diào)用相關(guān)代理方法,然后再在代理方法中回調(diào)相關(guān)的block,具體實(shí)現(xiàn)如下
在NSURLSessionDataDelegate回調(diào)時(shí),下面是獲取數(shù)據(jù)完成的代理
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 獲取任務(wù)對(duì)應(yīng)的delegate
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// 如果有delegate,則調(diào)用相關(guān)的代理方法
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
// 這里任務(wù)完成了,移除任務(wù)和代理
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
再來(lái)看AFURLSessionManagerTaskDelegate代理中相關(guān)實(shí)現(xiàn)
- (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];
});
});
});
}
}
這樣就實(shí)現(xiàn)每一個(gè)任務(wù)都有它自己?jiǎn)为?dú)的代理,完成后即進(jìn)行回調(diào),還有一個(gè)好處是,當(dāng)任務(wù)完成時(shí),就可以移除代理,這樣可以打破block的循環(huán)引用,所以我們?cè)貯F的block中直接在self不會(huì)造成循環(huán)引用
下面在看一下SSL相關(guān)類AFSecurityPolicy
- AFSecurityPolicy:它是為了驗(yàn)證證書的,至于HTTP和HTTPS的區(qū)別,這個(gè)在百度上有很多文章,我這里主要看AFSecurityPolicy都有哪些功能
@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>
// 返回SSL Pinning的類型
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
// 這個(gè)屬性保存著所有的可用做校驗(yàn)的證書的集合
// AFNetworking默認(rèn)會(huì)搜索工程中所有.cer的證書文件
// 如果想制定某些證書,可使用certificatesInBundle在目標(biāo)路徑下加載證書,然后調(diào)用policyWithPinningMode:withPinnedCertificates創(chuàng)建一個(gè)本類對(duì)象。
// 只要在證書集合中任何一個(gè)校驗(yàn)通過(guò),evaluateServerTrust:forDomain: 就會(huì)返回true,即通過(guò)校驗(yàn)
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
// 允許無(wú)效或過(guò)期的證書,默認(rèn)是不允許
@property (nonatomic, assign) BOOL allowInvalidCertificates;
// 是否驗(yàn)證證書中的域名domain
@property (nonatomic, assign) BOOL validatesDomainName;
// 返回指定bundle中的證書
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
// 默認(rèn)的實(shí)例對(duì)象,默認(rèn)的認(rèn)證設(shè)置為:
// 1. 不允許無(wú)效或過(guò)期的證書
// 2. 驗(yàn)證domain名稱
// 3. 不對(duì)證書和公鑰進(jìn)行驗(yàn)證
+ (instancetype)defaultPolicy;
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(nullable NSString *)domain;
@end
- 還一個(gè)問(wèn)題,就是線程安全問(wèn)題,在AF中用了很多GCD函數(shù)來(lái)保證線程安全
下面函數(shù)是用來(lái)保證任務(wù)創(chuàng)建安全的,AF給出的解釋是在iOS8.0以前,任務(wù)創(chuàng)建有線程安全問(wèn)題,如果你適配8.0以后的話,就不會(huì)用它了
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();
}
}
}
下面是處理代理回調(diào)的線程函數(shù),它是并行隊(duì)列,在多個(gè)回調(diào)同時(shí)觸發(fā)時(shí),可以同時(shí)處理,可以加快數(shù)據(jù)的處理速度
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;
}
下面是完成時(shí)的回調(diào)隊(duì)列,當(dāng)completionGroup屬性為nil時(shí),默認(rèn)就使用它
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;
}
下面再貼出完成時(shí)回調(diào)的代碼
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
// 請(qǐng)求出錯(cuò)
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
// 在completionQueue存在時(shí),則completionQueue中回調(diào),否則在主隊(duì)列中回調(diào)
self.completionHandler(task.response, responseObject, error);
}
dispatch_async(dispatch_get_main_queue(), ^{
// 在主線程中發(fā)出任務(wù)完成通知
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
} else {
// 請(qǐng)求成功
dispatch_async(url_session_manager_processing_queue(), ^{
// 子線程并行處理回調(diào)數(shù)據(jù)
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存在時(shí),則completionQueue中回調(diào),否則在主隊(duì)列中回調(diào)
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{
// 在主線程中發(fā)出任務(wù)完成通知
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
從上面代碼可以看出,在默認(rèn)情況下,不論我們?cè)谀膫€(gè)線程用AF做請(qǐng)求,它的回調(diào)永遠(yuǎn)是在主隊(duì)列中
到此AFNetworking文件下的類就全部讀完了,實(shí)際我讀AF就是想了解,在請(qǐng)求時(shí),AF到底都為我們做了什么,總結(jié)一下:
- 請(qǐng)求體NSURLRequest的封裝,涉及到構(gòu)建head信息、Request相關(guān)參數(shù)設(shè)置,請(qǐng)求參數(shù)序列化等
- 根據(jù)請(qǐng)求類型創(chuàng)建相關(guān)的任務(wù)NSURLSessionTask,涉及到任務(wù)回調(diào),線程安全等
- 返回?cái)?shù)據(jù)NSData的解析
- HTTPS的支持
這里只是簡(jiǎn)單的總結(jié)這4步,但是每一步的實(shí)現(xiàn)都不易,如果想深入了解的話還會(huì)涉及到更多的知識(shí)點(diǎn),同時(shí)也體會(huì)到寫一個(gè)優(yōu)秀的網(wǎng)絡(luò)框架實(shí)屬不易!