The process of realizing the download
One generates an NSMutableURLRequest
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:requestUrl parameters:nil error:nil];
[request setAllHTTPHeaderFields:[self requestHeader]];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer.timeoutInterval = 15;
Two create NSURLSessionTask
NSURLSessionTask *task = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
NSURL *pathURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];
return pathURL;
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
if (!error) {
[self performSelector:@selector(downloadFinish:) withObject:userInfo];
} else {
[self handleFailtureResponse:response error:error userInfo:userInfo];
[self performSelector:@selector(requestFailed:) withObject:userInfo];
}
}] ;
[task resume];
Create URLSessionTask process analysis
Generate NSURLSessionDownloadTask
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
return downloadTask;
}
Since the proxy of NSURLSession is AFURLSessionManager,
the proxy methods related to the network request of the system are all implemented by AFURLSessionManager, as shown in the figure
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
Implementation of addDelegateForDownloadTask method
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;
if (destination) {
delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
return destination(location, task.response);
};
}
downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:downloadTask];
delegate.downloadProgressBlock = downloadProgressBlock;
}
As can be seen from the above code, an AFURLSessionManagerTaskDelegate object is created, and the request completion callback, process
callback, and download completion callback downloadTaskDidFinishDownloading are passed to the AFURLSessionManagerTaskDelegate object
And through the following code
- (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];
}
It can be seen that the created AFURLSessionManagerTaskDelegate object is placed in the self.mutableTaskDelegatesKeyedByTaskIdentifier dictionary, and
task.taskIdentifier is used as the key
Proxy method call process
Let's take - (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location proxy method as an example
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
if ([location.pathExtension containsString:@"gif"]) {
}
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
if (self.downloadTaskDidFinishDownloading) {
NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
if (fileURL) {
delegate.downloadFileURL = fileURL;
NSError *error = nil;
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification object:downloadTask userInfo:nil];
}
return;
}
}
if (delegate) {
[delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];
}
}
As can be seen from the above code, in the proxy method, first obtain the AFURLSessionManagerTaskDelegate object, and then let the AFURLSessionManagerTaskDelegate object execute the method with the same name as the proxy method
Get the AFURLSessionManagerTaskDelegate object
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = nil;
[self.lock lock];
delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
[self.lock unlock];
return delegate;
}
The reason for this design
With the design of AFNetworking, the same AFURLSessionManager object
can be used to create multiple tasks for easy management