Skip to content

Commit 0fd1304

Browse files
author
孙春磊
committed
AFN中创建dataTask任务
1 parent 4e9b187 commit 0fd1304

File tree

2 files changed

+41
-32
lines changed

2 files changed

+41
-32
lines changed

AFN3.x阅读/AFN3.x阅读/AFNetworking3.x/AFNetworking/AFHTTPSessionManager.m

+4-1
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,12 @@ - (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
368368

369369
// 方法dataTaskWithRequest去拿到我们最终需要的NSURLSessionDataTask实例,并且在完成的回调里,调用我们传过来的成功和失败的回调
370370
__block NSURLSessionDataTask *dataTask = nil;
371+
371372
dataTask = [self dataTaskWithRequest:request
372373
uploadProgress:uploadProgress
373374
downloadProgress:downloadProgress
374375
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
376+
// 当传入的completionHandler被执行时,会回调到这里
375377
if (error) {
376378
if (failure) {
377379
failure(dataTask, error);
@@ -382,7 +384,8 @@ - (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
382384
}
383385
}
384386
}];
385-
387+
388+
386389
return dataTask;
387390
}
388391

AFN3.x阅读/AFN3.x阅读/AFNetworking3.x/AFNetworking/AFURLSessionManager.m

+37-31
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
#import "AFURLSessionManager.h"
2323
#import <objc/runtime.h>
24-
24+
/// 如果没有 NSFoundationVersionNumber_iOS_8_0 自己定义一个值 1140.11 否则使用系统定义的值
2525
#ifndef NSFoundationVersionNumber_iOS_8_0
2626
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
2727
#else
@@ -41,27 +41,18 @@ static dispatch_queue_t url_session_manager_creation_queue() {
4141
static void url_session_manager_create_task_safely(dispatch_block_t block) {
4242

4343
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
44+
4445
// Fix of bug
4546
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
4647
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
47-
48-
// 为什么用sync ?
49-
// 因为是想要主线程等在这,等执行完,在返回,因为必须执行完 dataTask才有数据,传值才有意义。
50-
51-
// 为什么要用串行队列?
52-
// 因为这块是为了防止ios8以下内部的dataTaskWithRequest是并发创建的, //这样会导致taskIdentifiers这个属性值不唯一,因为后续要用taskIdentifiers来作为Key对应delegate。
53-
54-
// 同步任务串行队列 不开线程顺序执行
55-
56-
dispatch_sync(url_session_manager_creation_queue(), block);
57-
5848
/**
59-
方法非常简单,关键是理解这么做的目的为什么我们不直接去调用
49+
方法非常简单,关键是理解这么做的目的:为什么我们不直接去调用?
6050
dataTask = [self.session dataTaskWithRequest:request];
61-
非要绕这么一圈,我们点进去bug日志里看看,原来这是为了适配iOS8的以下,创建session的时候,偶发的情况会出现session的属性taskIdentifier这个值不唯一,而这个taskIdentifier是我们后面来映射delegate的key,所以它必须是唯一的。
62-
具体原因应该是NSURLSession内部去生成task的时候是用多线程并发去执行的。想通了这一点,我们就很好解决了,我们只需要在iOS8以下同步串行的去生成task就可以防止这一问题发生(如果还是不理解同步串行的原因,可以看看注释)
51+
非要绕这么一圈,我们点进去bug日志里看看,原来这是为了适配iOS8的以下,创建session的时候,并发的情况会出现session的属性taskIdentifier这个值不唯一,而这个taskIdentifier是我们后面来映射delegate的key,所以它必须是唯一的。
52+
具体原因应该是NSURLSession内部去生成task的时候是用多线程并发去执行的。想通了这一点,我们就很好解决了,我们只需要在iOS8以下同步串行的去生成task就可以防止这一问题发生
6353
*/
6454

55+
dispatch_sync(url_session_manager_creation_queue(), block);
6556

6657
} else {
6758
// ios8以上 直接执行block
@@ -739,17 +730,24 @@ - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
739730
self.operationQueue.maxConcurrentOperationCount = 1;
740731

741732

742-
/**
733+
/** 方法要求该队列为串行队里
734+
An operation queue for scheduling the delegate calls and completion handlers. The queue should be a serial queue, in order to ensure the correct ordering of callbacks. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
735+
743736
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
744737
此处的协议是 NSURLSessionDelegate
745738
*/
746739
// 注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
747740
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
741+
742+
743+
748744

749745
// 各种响应转码 AFJSONResponseSerializer--AFHTTPResponseSerializer<AFURLResponseSerialization>
750746
self.responseSerializer = [AFJSONResponseSerializer serializer];
751747
// 设置默认安全策略
752748
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
749+
750+
753751

754752
#if !TARGET_OS_WATCH
755753
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
@@ -758,12 +756,13 @@ + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configur
758756
// 用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分
759757
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
760758

761-
// 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全
762759

763-
// MARK:<为什么需要使用‘锁’,需要有这个意识,没有意识的时候就多思考为什么代码要这么写,不这么写会出现什么问题>
760+
// 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全
764761
self.lock = [[NSLock alloc] init];
765762
self.lock.name = AFURLSessionManagerLockName;
766763

764+
765+
767766
// MARK:<关于后台下载的session还需要理解透彻>
768767
/** ?????????????? 关于后台下载的session 还是没理解到位 ??????????????
769768
这个方法用来异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有。我们打断点去看,也确实如此,里面的数组都是空的。
@@ -831,18 +830,19 @@ - (void)dealloc {
831830
}
832831

833832
#pragma mark -
834-
835833
- (NSString *)taskDescriptionForSessionTasks {
836-
// %p 内存地址
834+
// 使用AFURLSessionManager对象的内存地址描述task
837835
return [NSString stringWithFormat:@"%p", self];
838836
}
839837

838+
// AFURLSessionManager监听到task的开始和暂停的回调
840839
- (void)taskDidResume:(NSNotification *)notification {
841840
NSURLSessionTask *task = notification.object;
842841
if ([task respondsToSelector:@selector(taskDescription)]) {
843-
// task.taskDescription 之前会被赋值taskDescriptionForSessionTasks
842+
// 如果是被标记为self.taskDescriptionForSessionTasks的任务
844843
if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
845844
dispatch_async(dispatch_get_main_queue(), ^{
845+
// 发送任务继续的通知--AFN中与UI相关的分类会监听该通知
846846
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
847847
});
848848
}
@@ -854,6 +854,7 @@ - (void)taskDidSuspend:(NSNotification *)notification {
854854
if ([task respondsToSelector:@selector(taskDescription)]) {
855855
if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
856856
dispatch_async(dispatch_get_main_queue(), ^{
857+
// 发送任务挂起的通知--AFN中与UI相关的分类会监听该通知
857858
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
858859
});
859860
}
@@ -873,14 +874,19 @@ - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
873874
return delegate;
874875
}
875876

877+
/**
878+
设置Task的代理
879+
880+
@param delegate AF自定义的代理
881+
@param task 请求的task
882+
*/
876883
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
877884
forTask:(NSURLSessionTask *)task
878885
{
879886
// 断言,如果没有这个参数,debug下crash在这
880887
NSParameterAssert(task);
881888
NSParameterAssert(delegate);
882-
// MARK:<在操作NSDictionary时又出现了‘锁’>
883-
// 加锁保证字典线程安全
889+
// 加锁保证操作NSMutableDictionary时安全--NSMutableDictionary不是线程安全的
884890
[self.lock lock];
885891
// 将AFURLSessionManagerTaskDelegate放入以taskIdentifier标记的词典中(同一个NSURLSession中的taskIdentifier是唯一的)
886892
// 代理和task建立映射关系
@@ -905,18 +911,15 @@ - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
905911
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
906912
{
907913
// 创建AFURLSessionManagerTaskDelegate 并初始化
908-
// 对task的下载和上传进度进行了KVO
909914
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
910915

911-
// AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系
912-
// MARK:<manager属性是weak self不会被释放吗?>
916+
// AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系--为了防止循环引用使用weak引用manager
913917
delegate.manager = self;
914918

915919
delegate.completionHandler = completionHandler;
916920

917921
// 这个taskDescriptionForSessionTasks用来发送开始和挂起通知的时候会用到,就是用这个值来Post通知,来两者对应
918-
// MARK:<这个taskDescription有什么作用?>
919-
922+
// 将同一个AFURLSessionManger对象的所有Task的taskDescription标记成一个值
920923
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
921924

922925
// ***** 将AFURLSessionManagerTaskDelegate对象与 dataTask建立关系
@@ -1054,6 +1057,11 @@ - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerialize
10541057
}
10551058

10561059
#pragma mark -
1060+
1061+
/**
1062+
AFURLSessionManager添加对task开始和暂停的监听
1063+
@param task 请求任务
1064+
*/
10571065
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
10581066
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
10591067
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
@@ -1105,10 +1113,8 @@ - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
11051113
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
11061114

11071115
__block NSURLSessionDataTask *dataTask = nil;
1108-
//第一件事,创建NSURLSessionDataTask,里面适配了Ios8以下taskIdentifiers,函数创建task对象。 //其实现应该是因为iOS 8.0以下版本中会并发地创建多个task对象,而同步有没有做好,导致taskIdentifiers 不唯一…这边做了一个串行处理
1109-
// 不是太懂??
11101116

1111-
// 调用了一个url_session_manager_create_task_safely()函数,传了一个Block进去,Block里就是iOS原生生成dataTask的方法
1117+
// 在iOS 8.0以下版本中会并发地创建多个task对象时由于同步有没有做好,导致taskIdentifiers 不唯一(ios的bug)…这边做了一个串行处理
11121118
url_session_manager_create_task_safely(^{
11131119
// ios8以上直接创建dataTask
11141120
#pragma mark - dataTaskWithRequest

0 commit comments

Comments
 (0)