Skip to content

Commit a84541a

Browse files
committed
AFURLSessionManager的初始化
1 parent 923550b commit a84541a

File tree

2 files changed

+74
-36
lines changed

2 files changed

+74
-36
lines changed

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,16 @@ - (instancetype)initWithBaseURL:(NSURL *)url
7777
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
7878
// 对传过来的BaseUrl进行处理,如果有值且最后不包含/,url加上"/"
7979
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
80-
81-
82-
// If the original URL does not end with a forward slash(斜杠-分隔号“/”)) and pathComponent does not begin with a forward slash, a forward slash is inserted between the two parts of the returned URL, unless the original URL is the empty string
83-
80+
81+
/** URLByAppendingPathComponent方法
82+
If the original URL does not end with a forward slash(斜杠-分隔号“/”)) and pathComponent does not begin with a forward slash, a forward slash is inserted between the two parts of the returned URL, unless the original URL is the empty string
83+
如果url不带'/'后缀 且 pathComponent不是以'/'开头 该方法就会在两者之间插入'/'
84+
*/
8485
url = [url URLByAppendingPathComponent:@""];
8586
}
8687

88+
// 设置baseURL requestSerializer responseSerializer
8789
self.baseURL = url;
88-
8990
self.requestSerializer = [AFHTTPRequestSerializer serializer];
9091
self.responseSerializer = [AFJSONResponseSerializer serializer];
9192

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

+68-31
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,15 @@ static dispatch_group_t url_session_manager_completion_group() {
137137

138138

139139
/**
140-
NSURLSessionDataTask //一般的get、post等请求
141-
NSURLSessionUploadTask // 用于上传文件或者数据量比较大的请求
142-
NSURLSessionDownloadTask //用于下载文件或者数据量比较大的请求
143-
NSURLSessionStreamTask //建立一个TCP / IP连接的主机名和端口或一个网络服务对象。
140+
NSURLSessionDataTask // 一般的get、post等请求----请求得到数据存放在内存中
141+
NSURLSessionUploadTask // 用于上传文件或者数据量比较大的请求 -----可以上传本地文件、流
142+
NSURLSessionDownloadTask // 用于下载文件或者数据量比较大的请求-----下载的文件会临时写入沙盒
143+
NSURLSessionStreamTask // 建立一个TCP/IP连接的主机名和端口或一个网络服务对象。
144144
145145
*/
146146

147147
#pragma mark -
148-
148+
// 所有的task都有此代理来处理--所以遵循NSURLSessionTaskDelegate、NSURLSessionDataDelegate、NSURLSessionDownloadDelegate等不同类型task的代理方法
149149
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
150150
- (instancetype)initWithTask:(NSURLSessionTask *)task;
151151
@property (nonatomic, weak) AFURLSessionManager *manager;
@@ -168,30 +168,34 @@ - (instancetype)initWithTask:(NSURLSessionTask *)task {
168168
}
169169

170170
_mutableData = [NSMutableData data];
171+
172+
// MARK:<NSProgress 需要深入了解这个类>
171173
_uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
172174
_downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
173175

174176
__weak __typeof__(task) weakTask = task;
177+
// 配置_uploadProgress、_downloadProgress
175178
for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
176179
{
177180
progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
178181
progress.cancellable = YES;
179-
progress.cancellationHandler = ^{
182+
progress.cancellationHandler = ^{ // 取消的回调--取消任务
180183
[weakTask cancel];
181184
};
182185
progress.pausable = YES;
183-
progress.pausingHandler = ^{
186+
progress.pausingHandler = ^{ // 暂停回调--任务挂起
184187
[weakTask suspend];
185188
};
189+
// setResumingHandler: 该方法iOS9之后可以使用
186190
if ([progress respondsToSelector:@selector(setResumingHandler:)]) {
187191
progress.resumingHandler = ^{
188-
[weakTask resume];
192+
[weakTask resume]; // 任务恢复
189193
};
190194
}
191195
[progress addObserver:self
192196
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
193197
options:NSKeyValueObservingOptionNew
194-
context:NULL];
198+
context:NULL]; // 监听完成进度
195199
}
196200
return self;
197201
}
@@ -202,15 +206,17 @@ - (void)dealloc {
202206
}
203207

204208
#pragma mark - NSProgress Tracking
205-
209+
// downloadProgress、uploadProgress进度更新回调(KVO)
206210
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
207211
if ([object isEqual:self.downloadProgress]) {
208212
if (self.downloadProgressBlock) {
213+
// 使用者传入的下载进度回调
209214
self.downloadProgressBlock(object);
210215
}
211216
}
212217
else if ([object isEqual:self.uploadProgress]) {
213218
if (self.uploadProgressBlock) {
219+
// 使用者传入的上传进度回调
214220
self.uploadProgressBlock(object);
215221
}
216222
}
@@ -233,7 +239,7 @@ - (void)URLSession:(__unused NSURLSession *)session
233239
{
234240
// 所有的指针变量默认都是__strong类型,我们通常省略不写__strong
235241
// delegate中的AFURLSessionManager使用weak方式引用 这里使用__strong 防止被释放
236-
// 1)强引用self.manager,防止被提前释放;因为self.manager声明为weak,类似Block
242+
// 1)强引用self.manager,防止被提前释放;因为self.manager声明为weak
237243
__strong AFURLSessionManager *manager = self.manager;
238244

239245
__block id responseObject = nil;
@@ -394,7 +400,7 @@ - (void)URLSession:(NSURLSession *)session
394400
{
395401
self.downloadFileURL = nil;
396402
// AFSessionManager也有个downloadTaskDidFinishDownloading 1750行
397-
// 这个是“AFURLSessionManagerTaskDelegate”自定义的block(内部是用户自定义的block 看 900 行)
403+
// 此处的downloadTaskDidFinishDownloading是“AFURLSessionManagerTaskDelegate”的一个属性block(内部是用户自定义的block 看 900 行)
398404
// 这个是对应的每个task的,每个task可以设置各自下载路径
399405
if (self.downloadTaskDidFinishDownloading) {
400406
// 得到用户自定义下载路径
@@ -418,7 +424,7 @@ - (void)URLSession:(NSURLSession *)session
418424
/**
419425
a.之前的NSURLSession的代理和这里的AFURLSessionManagerTaskDelegate都移动了文件到下载路径,而NSUrlSession代理的下载路径是所有request公用的下载路径,一旦设置,所有的request都会下载到之前那个路径。
420426
421-
b.而这个是对应的每个task的,每个task可以设置各自下载路径 ??
427+
b.而这个是对应的每个task的,每个task可以设置各自下载路径
422428
解析 需要看在AFHTTPSessionManager中的一个方法
423429
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
424430
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
@@ -713,7 +719,6 @@ - (instancetype)init {
713719
return [self initWithSessionConfiguration:nil];
714720
}
715721

716-
717722
// AF3.x最最核心的类AFURLSessionManager。几乎所有的类都是围绕着这个类在处理业务逻辑。
718723
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
719724
self = [super init];
@@ -729,9 +734,10 @@ - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
729734

730735
self.operationQueue = [[NSOperationQueue alloc] init];
731736

732-
// 这个operationQueue就是我们代理回调的queue。这里把代理回调的线程并发数设置为1了。至于这里为什么要这么做,我们先留一个坑,等我们讲完AF2.x之后再来分析这一块。
733-
self.operationQueue.maxConcurrentOperationCount = 1;
737+
// TODO: <这个operationQueue就是我们代理回调的queue。这里把代理回调的线程并发数设置为1了。至于这里为什么要这么做,我们先留一个坑,等我们讲完AF2.x之后再来分析这一块>
734738

739+
self.operationQueue.maxConcurrentOperationCount = 1;
740+
735741

736742
/**
737743
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
@@ -740,7 +746,7 @@ + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configur
740746
// 注意代理,代理的继承,实际上NSURLSession去判断了,你实现了哪个方法会去调用,包括子代理的方法!
741747
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
742748

743-
// 各种响应转码
749+
// 各种响应转码 AFJSONResponseSerializer--AFHTTPResponseSerializer<AFURLResponseSerialization>
744750
self.responseSerializer = [AFJSONResponseSerializer serializer];
745751
// 设置默认安全策略
746752
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
@@ -749,33 +755,59 @@ + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configur
749755
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
750756
#endif
751757
// 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典(重点,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理)
752-
// 用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分,接下来我们会具体讲这一块
758+
// 用来让每一个请求task和我们自定义的AF代理来建立映射用的,其实AF对task的代理进行了一个封装,并且转发代理到AF自定义的代理,这是AF比较重要的一部分
753759
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
754760

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

759-
760-
/** ???
761-
767+
// MARK:<关于后台下载的session还需要理解透彻>
768+
/** ?????????????? 关于后台下载的session 还是没理解到位 ??????????????
762769
这个方法用来异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有。我们打断点去看,也确实如此,里面的数组都是空的。
763770
但是想想也知道,AF大神不会把一段没用的代码放在这吧。辗转多处,终于从AF的issue中找到了结论:https://github.com/AFNetworking/AFNetworking/issues/3499 。
764771
765-
原来这是为了从后台回来,重新初始化session,防止一些之前的后台请求任务,导致程序的crash。
772+
----来这是为了从后台回来,重新初始化session----,防止一些之前的'后台请求任务',导致程序的crash。
766773
ApplicationDelegate 的代理方法里边处理未完成的后台download session
767774
‘restoring a session from the background’ 这句话我理解是,有用同一个identifier 创建session的情况,一旦这种情况出现,会返回同一个session ,就需要对task进行获取和处理了
768-
769-
关于session的文档
775+
776+
关于session的文档
770777
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html#//apple_ref/doc/uid/10000165i-CH2-SW42
771778
*/
772779

773780
/**
774-
Asynchronously calls a completion callback with all data, upload, and download tasks in a session.
775-
The returned arrays contain any tasks that you have created within the session, not including any tasks that have been invalidated after completing, failing, or being cancelled.
781+
782+
可以结合这两篇内容去理解下
783+
https://realm.io/news/gwendolyn-weston-ios-background-networking/
784+
785+
http://stackoverflow.com/questions/23492311/nsurlsession-background-task-avoid-duplicates
786+
// 这篇介绍了后台下载的
787+
https://www.ralfebert.de/ios-examples/networking/urlsession-background-downloads/
788+
// 一个基于URLSession的功能完善的下载器
789+
https://www.jianshu.com/p/b4edfa0b71d8
790+
Qusetions:
791+
792+
Is there a way to query NSURLSession to return a list of background tasks? It seems possible to make duplicate requests for background download tasks. I do not get any error if I make the same url download request while a previous one is still in progress.
793+
794+
What is the best way to handle this situation? I can maintain a list of urls I am currently downloading from, but in case the app is relaunched I lose this reference. I can again store this information in persistent storage. But it just seems inconvenient not to have an option to query NSURLSession for this.
776795
796+
Answer:
777797
778-
可以结合这两篇内容去理解下 https://realm.io/news/gwendolyn-weston-ios-background-networking/ http://stackoverflow.com/questions/23492311/nsurlsession-background-task-avoid-duplicates 在这里这个防御编程的作用是为了应对session在执行后台下载任务的情况。进入后台后在ApplicationDelegate那个方法中被唤醒,我们会去创建相同identifier的session,这个时候需要通过 getTasksWithCompletionHandler去获取未来得及执行的tasks去做一些防止崩溃的处理。
798+
You could get the list of all download tasks added to the session with the following call.
799+
800+
[[self defaultSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
801+
}];
802+
803+
在这里这个防御编程的作用是为了应对session在执行后台下载任务的情况。进入后台后在ApplicationDelegate那个方法中被唤醒,我们会去创建相同identifier的session,这个时候需要通过 getTasksWithCompletionHandler去获取未来得及执行的tasks去做一些防止崩溃的处理。
804+
*/
805+
806+
/**
807+
getTasksWithCompletionHandler:
808+
获取后台没有完成的Tasks
809+
Asynchronously calls a completion callback with all data, upload, and download tasks in a session.
810+
The returned arrays contain any tasks that you have created within the session, not including any tasks that have been invalidated after completing, failing, or being cancelled.
779811
*/
780812
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
781813
for (NSURLSessionDataTask *task in dataTasks) {
@@ -847,9 +879,11 @@ - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
847879
// 断言,如果没有这个参数,debug下crash在这
848880
NSParameterAssert(task);
849881
NSParameterAssert(delegate);
882+
// MARK:<在操作NSDictionary时又出现了‘锁’>
850883
// 加锁保证字典线程安全
851884
[self.lock lock];
852885
// 将AFURLSessionManagerTaskDelegate放入以taskIdentifier标记的词典中(同一个NSURLSession中的taskIdentifier是唯一的)
886+
// 代理和task建立映射关系
853887
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
854888

855889
// 此版本有更改 版3.1.0此处还有个操作
@@ -875,11 +909,14 @@ - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
875909
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
876910

877911
// AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系
912+
// MARK:<manager属性是weak self不会被释放吗?>
878913
delegate.manager = self;
879914

880915
delegate.completionHandler = completionHandler;
881916

882917
// 这个taskDescriptionForSessionTasks用来发送开始和挂起通知的时候会用到,就是用这个值来Post通知,来两者对应
918+
// MARK:<这个taskDescription有什么作用?>
919+
883920
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
884921

885922
// ***** 将AFURLSessionManagerTaskDelegate对象与 dataTask建立关系
@@ -894,7 +931,7 @@ - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
894931
1)这个方法,生成了一个AFURLSessionManagerTaskDelegate,这个其实就是AF的自定义代理。我们请求传来的参数,都赋值给这个AF的代理了。
895932
2)delegate.manager = self;代理把AFURLSessionManager这个类作为属性了,我们可以看到:
896933
@property (nonatomic, weak) AFURLSessionManager *manager;
897-
这个属性是弱引用的,所以不会存在循环引用的问题。
934+
这个属性是弱引用的,所以不会存在循环引用的问题。 (manage->delegate delegate-->manager)
898935
899936
3)我们调用了[self setDelegate:delegate forTask:dataTask];
900937
*/
@@ -924,16 +961,16 @@ - (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
924961
delegate.manager = self;
925962
delegate.completionHandler = completionHandler;
926963

927-
// 如果用户设置了destination这个block 看 380 行
964+
// 如果用户设置了destination这个block(即用户设置了下载文件存放的路径) 看 380 行
928965
if (destination) {
929966

930967
//有点绕,就是把一个block赋值给“AF代理”的downloadTaskDidFinishDownloading,这个Block里的内部返回也是调用Block去获取到的,这里面的参数都是“AF代理”传来的。
931968
delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
932-
// 调用用户传入的destination这个block
969+
// 调用用户传入的destination这个block (将下载文件的临时路径-location和响应信息传给用户-task.response)
933970
return destination(location, task.response);
934971
};
935972
}
936-
/**
973+
/** 下载文件临时存放在 ‘/tem’ 文件夹下
937974
(lldb) po location
938975
file:///private/var/mobile/Containers/Data/Application/CC27F214-F815-45AF-96D4-8EA0C5C1A215/tmp/CFNetworkDownload_iykDD1.tmp
939976

0 commit comments

Comments
 (0)