21
21
22
22
#import " AFURLSessionManager.h"
23
23
#import < objc/runtime.h>
24
-
24
+ // / 如果没有 NSFoundationVersionNumber_iOS_8_0 自己定义一个值 1140.11 否则使用系统定义的值
25
25
#ifndef NSFoundationVersionNumber_iOS_8_0
26
26
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
27
27
#else
@@ -41,27 +41,18 @@ static dispatch_queue_t url_session_manager_creation_queue() {
41
41
static void url_session_manager_create_task_safely (dispatch_block_t block) {
42
42
43
43
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
44
+
44
45
// Fix of bug
45
46
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
46
47
// 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
-
58
48
/* *
59
- 方法非常简单,关键是理解这么做的目的: 为什么我们不直接去调用
49
+ 方法非常简单,关键是理解这么做的目的: 为什么我们不直接去调用?
60
50
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就可以防止这一问题发生
63
53
*/
64
54
55
+ dispatch_sync (url_session_manager_creation_queue (), block);
65
56
66
57
} else {
67
58
// ios8以上 直接执行block
@@ -739,17 +730,24 @@ - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
739
730
self.operationQueue .maxConcurrentOperationCount = 1 ;
740
731
741
732
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
+
743
736
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
744
737
此处的协议是 NSURLSessionDelegate
745
738
*/
746
739
// 注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
747
740
self.session = [NSURLSession sessionWithConfiguration: self .sessionConfiguration delegate: self delegateQueue: self .operationQueue];
741
+
742
+
743
+
748
744
749
745
// 各种响应转码 AFJSONResponseSerializer--AFHTTPResponseSerializer<AFURLResponseSerialization>
750
746
self.responseSerializer = [AFJSONResponseSerializer serializer ];
751
747
// 设置默认安全策略
752
748
self.securityPolicy = [AFSecurityPolicy defaultPolicy ];
749
+
750
+
753
751
754
752
#if !TARGET_OS_WATCH
755
753
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager ];
@@ -758,12 +756,13 @@ + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configur
758
756
// 用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分
759
757
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc ] init ];
760
758
761
- // 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全
762
759
763
- // MARK:<为什么需要使用‘锁’,需要有这个意识,没有意识的时候就多思考为什么代码要这么写,不这么写会出现什么问题>
760
+ // 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全
764
761
self.lock = [[NSLock alloc ] init ];
765
762
self.lock .name = AFURLSessionManagerLockName;
766
763
764
+
765
+
767
766
// MARK:<关于后台下载的session还需要理解透彻>
768
767
/* * ?????????????? 关于后台下载的session 还是没理解到位 ??????????????
769
768
这个方法用来异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有。我们打断点去看,也确实如此,里面的数组都是空的。
@@ -831,18 +830,19 @@ - (void)dealloc {
831
830
}
832
831
833
832
#pragma mark -
834
-
835
833
- (NSString *)taskDescriptionForSessionTasks {
836
- // %p 内存地址
834
+ // 使用AFURLSessionManager对象的内存地址描述task
837
835
return [NSString stringWithFormat: @" %p " , self ];
838
836
}
839
837
838
+ // AFURLSessionManager监听到task的开始和暂停的回调
840
839
- (void )taskDidResume : (NSNotification *)notification {
841
840
NSURLSessionTask *task = notification.object ;
842
841
if ([task respondsToSelector: @selector (taskDescription )]) {
843
- // task.taskDescription 之前会被赋值taskDescriptionForSessionTasks
842
+ // 如果是被标记为self.taskDescriptionForSessionTasks的任务
844
843
if ([task.taskDescription isEqualToString: self .taskDescriptionForSessionTasks]) {
845
844
dispatch_async (dispatch_get_main_queue (), ^{
845
+ // 发送任务继续的通知--AFN中与UI相关的分类会监听该通知
846
846
[[NSNotificationCenter defaultCenter ] postNotificationName: AFNetworkingTaskDidResumeNotification object: task];
847
847
});
848
848
}
@@ -854,6 +854,7 @@ - (void)taskDidSuspend:(NSNotification *)notification {
854
854
if ([task respondsToSelector: @selector (taskDescription )]) {
855
855
if ([task.taskDescription isEqualToString: self .taskDescriptionForSessionTasks]) {
856
856
dispatch_async (dispatch_get_main_queue (), ^{
857
+ // 发送任务挂起的通知--AFN中与UI相关的分类会监听该通知
857
858
[[NSNotificationCenter defaultCenter ] postNotificationName: AFNetworkingTaskDidSuspendNotification object: task];
858
859
});
859
860
}
@@ -873,14 +874,19 @@ - (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
873
874
return delegate;
874
875
}
875
876
877
+ /* *
878
+ 设置Task的代理
879
+
880
+ @param delegate AF自定义的代理
881
+ @param task 请求的task
882
+ */
876
883
- (void )setDelegate : (AFURLSessionManagerTaskDelegate *)delegate
877
884
forTask : (NSURLSessionTask *)task
878
885
{
879
886
// 断言,如果没有这个参数,debug下crash在这
880
887
NSParameterAssert (task);
881
888
NSParameterAssert (delegate);
882
- // MARK:<在操作NSDictionary时又出现了‘锁’>
883
- // 加锁保证字典线程安全
889
+ // 加锁保证操作NSMutableDictionary时安全--NSMutableDictionary不是线程安全的
884
890
[self .lock lock ];
885
891
// 将AFURLSessionManagerTaskDelegate放入以taskIdentifier标记的词典中(同一个NSURLSession中的taskIdentifier是唯一的)
886
892
// 代理和task建立映射关系
@@ -905,18 +911,15 @@ - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
905
911
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
906
912
{
907
913
// 创建AFURLSessionManagerTaskDelegate 并初始化
908
- // 对task的下载和上传进度进行了KVO
909
914
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc ] initWithTask: dataTask];
910
915
911
- // AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系
912
- // MARK:<manager属性是weak self不会被释放吗?>
916
+ // AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系--为了防止循环引用使用weak引用manager
913
917
delegate.manager = self;
914
918
915
919
delegate.completionHandler = completionHandler;
916
920
917
921
// 这个taskDescriptionForSessionTasks用来发送开始和挂起通知的时候会用到,就是用这个值来Post通知,来两者对应
918
- // MARK:<这个taskDescription有什么作用?>
919
-
922
+ // 将同一个AFURLSessionManger对象的所有Task的taskDescription标记成一个值
920
923
dataTask.taskDescription = self.taskDescriptionForSessionTasks ;
921
924
922
925
// ***** 将AFURLSessionManagerTaskDelegate对象与 dataTask建立关系
@@ -1054,6 +1057,11 @@ - (void)setResponseSerializer:(id <AFURLResponseSerialization>)responseSerialize
1054
1057
}
1055
1058
1056
1059
#pragma mark -
1060
+
1061
+ /* *
1062
+ AFURLSessionManager添加对task开始和暂停的监听
1063
+ @param task 请求任务
1064
+ */
1057
1065
- (void )addNotificationObserverForTask : (NSURLSessionTask *)task {
1058
1066
[[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (taskDidResume: ) name: AFNSURLSessionTaskDidResumeNotification object: task];
1059
1067
[[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (taskDidSuspend: ) name: AFNSURLSessionTaskDidSuspendNotification object: task];
@@ -1105,10 +1113,8 @@ - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
1105
1113
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
1106
1114
1107
1115
__block NSURLSessionDataTask *dataTask = nil ;
1108
- // 第一件事,创建NSURLSessionDataTask,里面适配了Ios8以下taskIdentifiers,函数创建task对象。 //其实现应该是因为iOS 8.0以下版本中会并发地创建多个task对象,而同步有没有做好,导致taskIdentifiers 不唯一…这边做了一个串行处理
1109
- // 不是太懂??
1110
1116
1111
- // 调用了一个url_session_manager_create_task_safely()函数,传了一个Block进去,Block里就是iOS原生生成dataTask的方法
1117
+ // 在iOS 8.0以下版本中会并发地创建多个task对象时由于同步有没有做好,导致taskIdentifiers 不唯一(ios的bug)…这边做了一个串行处理
1112
1118
url_session_manager_create_task_safely (^{
1113
1119
// ios8以上直接创建dataTask
1114
1120
#pragma mark - dataTaskWithRequest
0 commit comments