AFNetworking 源碼閱讀(v3.2.1)

AFNetworking項(xiàng)目地址 https://github.com/AFNetworking/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òu)建請(qǐng)求發(fā)放申明

下面貼出第一個(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表示它能解析的類型
    1. AFHTTPResponseSerializer:不做處理,直接返回NSData
    2. AFJSONResponseSerializer:JSON
    3. AFXMLParserResponseSerializer:xml
    4. AFXMLDocumentResponseSerializer:(Mac OS X) iPhone不能直接使用,需要用GData-XML
    5. AFPropertyListResponseSerializer:plist
    6. AFImageResponseSerializer:image
    7. 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é)一下:

  1. 請(qǐng)求體NSURLRequest的封裝,涉及到構(gòu)建head信息、Request相關(guān)參數(shù)設(shè)置,請(qǐng)求參數(shù)序列化等
  2. 根據(jù)請(qǐng)求類型創(chuàng)建相關(guān)的任務(wù)NSURLSessionTask,涉及到任務(wù)回調(diào),線程安全等
  3. 返回?cái)?shù)據(jù)NSData的解析
  4. HTTPS的支持

這里只是簡(jiǎn)單的總結(jié)這4步,但是每一步的實(shí)現(xiàn)都不易,如果想深入了解的話還會(huì)涉及到更多的知識(shí)點(diǎn),同時(shí)也體會(huì)到寫一個(gè)優(yōu)秀的網(wǎng)絡(luò)框架實(shí)屬不易!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們先看一下AFNetworking.h文件都給了我們什么方法 #import <Foundation/Found...
    瀟巖閱讀 775評(píng)論 0 1
  • 一. 前言 AFNetWorking的使用率非常高,這個(gè)不必多說(shuō)。無(wú)論是AFNetWorking還是SDWebIm...
    WellsCai閱讀 1,300評(píng)論 0 1
  • AFNetworking網(wǎng)絡(luò)框架在iOS開發(fā)中的霸主地位已經(jīng)根深蒂固,本篇將基于3.2.1版本對(duì)框架的幾個(gè)核心模塊...
    Lotheve閱讀 3,476評(píng)論 1 26
  • 接著上一篇的內(nèi)容往下講,如果沒看過(guò)上一篇內(nèi)容可以點(diǎn)這: AFNetworking到底做了什么? 之前我們講到NSU...
    涂耀輝閱讀 21,388評(píng)論 28 162
  • AFNetworking是我們常用的網(wǎng)絡(luò)庫(kù),我們有必要對(duì)其有必要的了解,以便進(jìn)行二次封裝和遇到問(wèn)題時(shí)能及時(shí)的進(jìn)行調(diào)...
    智小融閱讀 521評(píng)論 1 1

友情鏈接更多精彩內(nèi)容