源码阅读:AFNetworking(一)——从使用入手

源码阅读:AFNetworking(一)——从使用入手

IOS小彩虹2021-08-17 23:14:42160A+A-

该文章阅读的AFNetworking的版本为3.2.0。

1.初始化

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

AFHTTPSessionManager类中所有的初始化方法最终都会调用到- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration方法中

- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    // 首先调用了父类AFURLSessionManager的初始化方法
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }

    // 如果有效的url后没有正斜线“/”就添加上正斜线“/”
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    // 记录url 
    self.baseURL = url;

    // 实例化请求和响应序列化对象
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}

在其父类AFURLSessionManager类中的- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration中做了基本属性的初始化

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    // 初始化NSURLSessionConfiguration如果没有传则用默认
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }
    self.sessionConfiguration = configuration;

    // 初始化一个操作队列并设置最大线程并发数为1
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    // 利用已经初始化好的NSURLSessionConfiguration和NSOperationQueue初始化NSURLSession并遵守了代理
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    // 初始化JSON响应序列对象
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    // 初始化安全策略
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

    // 初始化网络状态监测对象
#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    // 初始化可变字典保存NSURLSessionTask和其对应的delegate,并以NSURLSessionTask的属性taskIdentifier做key,以NSURLSession的delegate做value
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    // 初始化self.mutableTaskDelegatesKeyedByTaskIdentifier可变字典的锁,确保字典在多线程访问时的线程安全
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    // 异步的获取当前session的所有未完成的task,并进行置空处理,主要是为了从后台切换到前台时重新初始化session
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}

2.进行网络请求

以GET请求为例

[manager GET:URLString parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"下载进度:%@", downloadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"响应对象:%@", responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"错误:%@", error);
    }];

点击进入方法中

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(id)parameters
                     progress:(void (^)(NSProgress * _Nonnull))downloadProgress
                      success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                      failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{

    // 生成一个NSURLSessionDataTask对象
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
                                                        URLString:URLString
                                                       parameters:parameters
                                                   uploadProgress:nil
                                                 downloadProgress:downloadProgress
                                                          success:success
                                                          failure:failure];

    // 开始任务
    [dataTask resume];

    return dataTask;
}

发现所有的请求方法无论是GET、POST还是其他都调用了同一个方法

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

    // 把所有的参数解析拼接生成一个NSMutableURLRequest对象,如果无法解析则回调返回错误
    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) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
#pragma clang diagnostic pop
        }

        return nil;
    }

    // 用生成的NSMutableURLRequest对象生成一个NSURLSessionDataTask对象并回调成功或失败
    __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;
}

2.1生成NSURLRequest对象

先看在AFURLRequestSerialization类中如何利用各种参数生成NSMutableURLRequest对象

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error
{
   
    // 在debug模式下如果缺少参数则会crash
    NSParameterAssert(method);
    NSParameterAssert(URLString);

    NSURL *url = [NSURL URLWithString:URLString];

    NSParameterAssert(url);

    // 生成NSMutableURLRequest对象并设置请求方式
    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    mutableRequest.HTTPMethod = method;

    // 遍历AFHTTPRequestSerializer的各个属性
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        // 如果发现有正在被观察的属性
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            // 把本类对应属性的值赋给NSMutableURLRequest对应的属性
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    // 将传入的parameters添加到mutableRequest中
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

	return mutableRequest;
}
  1. 首先,在这个方法中有一个C语言函数static NSArray *AFHTTPRequestSerializerObservedKeyPaths()这个函数实际上是将AFHTTPRequestSerializer类中一些属性的名字封装成字符串并以数组形式返回
  2. 其次,self.mutableObservedChangedKeyPaths这个属性在AFURLRequestSerialization的初始化方法- (instancetype)init中进行了初始化
self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    // 观察AFHTTPRequestSerializerObservedKeyPaths()函数返回的属性
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }

并在KVO方法中进行赋值

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(__unused id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (context == AFHTTPRequestSerializerObserverContext) {
        // 如果给当前属性赋的值不为null就添加到self.mutableObservedChangedKeyPaths中,否则从其中移除
        if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
            [self.mutableObservedChangedKeyPaths removeObject:keyPath];
        } else {
            [self.mutableObservedChangedKeyPaths addObject:keyPath];
        }
    }
}

由此所以我们可以得知self.mutableObservedChangedKeyPaths中保存的就是我们设置的AFHTTPRequestSerializer对象的属性的集合

  1. 最后,调用方法[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error]parameters编码并设置到mutableRequest中
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(id)parameters
                                        error:(NSError *__autoreleasing *)error
{
    // 在debug模式下如果缺少NSURLRequest对象则会crash
    NSParameterAssert(request);

    NSMutableURLRequest *mutableRequest = [request mutableCopy];

    // 遍历并对request没有的属性进行赋值
    [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
        if (![request valueForHTTPHeaderField:field]) {
            [mutableRequest setValue:value forHTTPHeaderField:field];
        }
    }];

    // 把parameters编码成字符串
    NSString *query = nil;
    if (parameters) {
        // 如果自定义了参数编码方式
        if (self.queryStringSerialization) {
            NSError *serializationError;
            // 用户可通过block自定义参数的编码方式
            query = self.queryStringSerialization(request, parameters, &serializationError);

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

                return nil;
            }
        // 使用默认的参数编码方式
        } else {
            switch (self.queryStringSerializationStyle) {
                case AFHTTPRequestQueryStringDefaultStyle:
                    query = AFQueryStringFromParameters(parameters);
                    break;
            }
        }
    }
    // 判断是否是GET、HEAD、DELETE请求,self.HTTPMethodsEncodingParametersInURI这个属性在AFURLRequestSerialization的初始化方法- (instancetype)init中进行了初始化
    if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
        if (query && query.length > 0) {
            // 将编码好的参数拼接在url后面
            mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
        }
    // 如果是POST、PUT请求
    } else {
        // #2864: an empty string is a valid x-www-form-urlencoded payload
        if (!query) {
            query = @"";
        }
        if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
            [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        }
        // 把编码好的参数拼到http的body中
        [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
    }

    return mutableRequest;
}

大概的看一下AFNetworking默认的的参数编码方式,AFQueryStringFromParameters()点进去以后可以看到是三个方法

NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
    NSMutableArray *mutablePairs = [NSMutableArray array];
    // 遍历由集合对象处理成AFQueryStringPair元素组成的数组
    for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
        // 把AFQueryStringPair元素的属性拼接成字符串添加到mutablePairs中,如果有value值就拼接成“field=value”的形式,否则为“field”
        [mutablePairs addObject:[pair URLEncodedStringValue]];
    }

    // 把mutablePairs中的字符串用&链接成一个字符串
    return [mutablePairs componentsJoinedByString:@"&"];
}

NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
    return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
}

NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
    NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];

    // 设置排序描述为按照对象的description属性升序排列
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];

    // 如果value是NSDictionary
    if ([value isKindOfClass:[NSDictionary class]]) {
        // 将NSDictionary的key按照首字母升序排列后遍历出nestedKey及其对应的nestedValue,然后递归调用AFQueryStringPairsFromKeyAndValue()方法,如果有key值则传(key[nestedKey], nestedValue),否则传(nestedKey, nestedValue)
        NSDictionary *dictionary = value;
        for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
            id nestedValue = dictionary[nestedKey];
            if (nestedValue) {
                [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
            }
        }
    // 如果value是NSArray
    } else if ([value isKindOfClass:[NSArray class]]) {
        // 直接遍历取出nestedValue,然后递归调用AFQueryStringPairsFromKeyAndValue()方法,如果有key值则传递(key[], nestedValue),否则传((null)[], nestedValue)
        NSArray *array = value;
        for (id nestedValue in array) {
            [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
        }
    // 如果value是NSSet
    } else if ([value isKindOfClass:[NSSet class]]) {
        // 将NSSet的值按照首字母升序排列后遍历出值obj,然后递归调用AFQueryStringPairsFromKeyAndValue()方法,如果有key值则传(key, obj),否则传((null), obj)
        NSSet *set = value;
        for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
            [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
        }
    // 如果value不是集合对象
    } else {
        实例化AFQueryStringPair对象添加到mutableQueryStringComponents数组中,也就是说AFQueryStringPairsFromKeyAndValue()这个方法执行结束后,返回的是由集合对象转化为AFQueryStringPair对象的元素组成的数组
        [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
    }

    return mutableQueryStringComponents;
}

至此,实例化NSMutableURLRequest对象的任务就结束了,然后就需要再回到- (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这个方法中,利用上一步实例化好的NSURLSessionDataTask对象request生成网络请求任务NSURLSessionDataTask

2.2 生成NSURLSessionTask对象

- (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(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

发现dataTask并不是直接创建,而是在一个block中创建,点进url_session_manager_create_task_safely可以看到这其实是做了一个版本的兼容

static void url_session_manager_create_task_safely(dispatch_block_t block) {
    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
        // 苹果在iOS8的时候已经解决了这个bug,这是为了兼容iOS8之前
        dispatch_sync(url_session_manager_creation_queue(), block);
    } else {
        block();
    }
}

这里作者自定义了一个串行队列,并且只生成一次

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

因此,可以发现如果是在iOS8之前的版本创建dataTask是在一个同步串行队列里,通过查找资料,可以知道在iOS8之前- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;这个方法是异步并发执行的,所以会出现实际回调completionHandlers并不是当初task的回调,而是另一个task的回调。

接下来是对生成的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的对象并和NSURLSessionDataTask对象以及AFURLSessionManager对象相关联
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

    delegate.uploadProgressBlock = uploadProgressBlock;
    delegate.downloadProgressBlock = downloadProgressBlock;
}

接着点[self setDelegate:delegate forTask:dataTask];进去

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    // 在debug模式下如果缺少参数则会crash
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    // 加锁保证对字典的操作线程安全
    [self.lock lock];
    // 将NSURLSessionTask对象的taskIdentifier作为key,将与之对应的AFURLSessionManagerTaskDelegate对象作为value,存放到字典中
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    // 为task添加开始与暂停通知
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

1.在[self addNotificationObserverForTask:task];方法中添加对task相关通知的接收

- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
    // 接收task开启和暂停的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}

在通知的响应方法中转化为AFNetworking对外暴漏的通知AFNetworkingTaskDidResumeNotificationAFNetworkingTaskDidSuspendNotification

- (void)taskDidResume:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
            });
        }
    }
}

- (void)taskDidSuspend:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
            });
        }
    }
}

为什么不直接发送通知,而是先接收通知然后经过处理后再发送通知呢?这是因为AFNetworkingNSURLSessionTasksuspendresume方法利用runtimeMethod Swizzling交换为af_suspendaf_resume,并在交换后的方法中发送通知以实现对task开始与暂停的监听, 但是在一个项目中可能有的网络请求不是当前session的,所以要通过task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks进行判断这个网络请求task是否来自当前session,其中self.taskDescriptionForSessionTasks其实就是AFURLSessionManager对象的指针字符串

- (NSString *)taskDescriptionForSessionTasks {
    return [NSString stringWithFormat:@"%p", self];
}

到此为止,对task的处理就结束了。

3.请求回调

AFURLSessionManager遵守了<NSURLSessionDelegate> <NSURLSessionTaskDelegate> <NSURLSessionDataDelegate> <NSURLSessionDownloadDelegate>四个代理并实现了15个代理方法

AFURLSessionManager实现的delegate.jpeg
这其中 AFURLSessionManagerTaskDelegate只实现了其中6个
AFURLSessionManagerTaskDelegate实现的delegate.jpeg
1.先看第一个代理 - (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error的实现

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    // 因为self.manager属性关键字是weak,所以为了防止被释放就用__strong
    __strong AFURLSessionManager *manager = self.manager;

    // 用来保存请求返回的数据,为了可以在block中进行修改,用了__block
    __block id responseObject = nil;

    // 用来保存发送通知时传递的数据,为了可以在block中进行修改,用了__block,并进行赋值
    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

    // 使用临时变量保存请求到的数据,并把保存数据的属性清空,节约内存
    //Performance Improvement from #2672
    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];
        //We no longer need the reference, so nil it out to gain back some memory.
        self.mutableData = nil;
    }

    // 如果设置了下载文件的保存路径,就传递保存路径,否则如果有请求到的数据,就传递请求到的数据
    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }

    // 如果请求出错
    if (error) {
        // 传递错误信息
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;

        // 用户可以自定义调度组和队列并利用dispatch_group_notify实现对回调完成的监控
        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];
                });
            });
        });
    }
}

2.第二个代理- (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data的实现相对简单

- (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    // 更新下载进度对象的属性
    self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
    self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;

    // 保存传递的数据
    [self.mutableData appendData:data];
}

3.第三个代理- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend是在向服务器传递数据时调用

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
    
    // 更新上传进度对象的属性
    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.uploadProgress.completedUnitCount = task.countOfBytesSent;
}

4.第四个代理是在执行下载任务时,定期调用的

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    
    // 更新下载进度对象的属性
    self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
    self.downloadProgress.completedUnitCount = totalBytesWritten;
}

5.第五个代理在重启下载时调用

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{
    
    // 更新下载进度对象的属性
    self.downloadProgress.totalUnitCount = expectedTotalBytes;
    self.downloadProgress.completedUnitCount = fileOffset;
}

6.第六个代理- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location是下载任务完成后的回调

- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
    // 如果用户设置了保存下载文件的路径,就将下载完的文件从临时路径移动过去,移动完成后发送通知
    self.downloadFileURL = nil;

    if (self.downloadTaskDidFinishDownloading) {
        self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
        if (self.downloadFileURL) {
            NSError *fileManagerError = nil;

            if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
                [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
            }
        }
    }
}

4.总结

到此为止,一个GET请求就结束了,总结一下AFNetworking做的事情

  • 首先,AFHTTPSessionManager利用参数methodURLStringparameters生成一个NSMutableURLRequest对象request
  • 然后,AFURLSessionManager利用生成的request生成一个NSURLSessionDataTask对象dataTask
  • 接下来,把dataTaskAFURLSessionManagerTaskDelegate的对象delegate利用字典一一对应保存,将delegate的进度属性的取消、暂停和开始和dataTask相对的方法相关联,并对delegatedataTask的相关属性添加观察者对delegate的上传下载进度属性赋值
  • 并且,为dataTask的开始于停止添加通知监听,并向外部发送通知
  • 接着,调用dataTaskresume方法进行网络请求
  • 最后,通过AFURLSessionManagerTaskDelegate的对象delegate实现的六个代理方法监听进度以及处理请求返回的数据,如果需要解析数据会在异步并发队列中进行,然后在最开始生成的最大并发数为1的NSOperationQueue的对象operationQueue串行回调结果。

源码阅读系列:AFNetworking

源码阅读:AFNetworking(一)——从使用入手

源码阅读:AFNetworking(二)——AFURLRequestSerialization

源码阅读:AFNetworking(三)——AFURLResponseSerialization

源码阅读:AFNetworking(四)——AFSecurityPolicy

源码阅读:AFNetworking(五)——AFNetworkReachabilityManager

源码阅读:AFNetworking(六)——AFURLSessionManager

源码阅读:AFNetworking(七)——AFHTTPSessionManager

源码阅读:AFNetworking(八)——AFAutoPurgingImageCache

源码阅读:AFNetworking(九)——AFImageDownloader

源码阅读:AFNetworking(十)——AFNetworkActivityIndicatorManager

源码阅读:AFNetworking(十一)——UIActivityIndicatorView+AFNetworking

源码阅读:AFNetworking(十二)——UIButton+AFNetworking

源码阅读:AFNetworking(十三)——UIImageView+AFNetworking

源码阅读:AFNetworking(十四)——UIProgressView+AFNetworking

源码阅读:AFNetworking(十五)——UIRefreshControl+AFNetworking

源码阅读:AFNetworking(十六)——UIWebView+AFNetworking

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们