ダウンロード要求を実現するための AFNetworking の主なプロセス

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;

2 つは 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];

URLSessionTask プロセス分析の作成

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

NSURLSessionのプロキシはAFURLSessionManagerであるため、
図に示すように、システムのネットワークリクエストに関連するプロキシメソッドはすべてAFURLSessionManagerによって実装されます。
画像の説明を追加してください

@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>

addDelegateForDownloadTask メソッドの実装

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

上記のコードからわかるように、AFURLSessionManagerTaskDelegate オブジェクトが作成され、要求完了コールバック、プロセス
コールバック、およびダウンロード完了コールバック downloadTaskDidFinishDownloading が AFURLSessionManagerTaskDelegate オブジェクトに渡されます。

そして、次のコードを通して

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


作成した AFURLSessionManagerTaskDelegate オブジェクトが self.mutableTaskDelegatesKeyedByTaskIdentifier ディクショナリに配置され、キーとして task.taskIdentifier が使用されていることがわかります。

プロキシメソッド呼び出し処理


(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
DidFinishDownloadingToURL:(NSURL *)location プロキシ メソッドを例に挙げてみましょう。

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

上記のコードからわかるように、プロキシ メソッドでは、まず AFURLSessionManagerTaskDelegate オブジェクトを取得し、次に AFURLSessionManagerTaskDelegate オブジェクトにプロキシ メソッドと同じ名前のメソッドを実行させます。

AFURLSessionManagerTaskDelegate オブジェクトを取得する

- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];

    return delegate;
}

画像の説明を追加してください

このデザインの理由

AFNetworking の設計では、同じ AFURLSessionManager オブジェクトを
使用して複数のタスクを作成し、管理を容易にすることができます。

おすすめ

転載: blog.csdn.net/LIUXIAOXIAOBO/article/details/132678198