• IOS 开发 网络详解(十一) AFURLSessionManager


    前言:URLSesstion实现网络请求的步骤

    // step1. 初始化AFURLSessionManager对象
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    
    // step2. 获取AFURLSessionManager的task对象
        NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
            if (error) {
                NSLog(@"Error: %@", error);
            } else {
                NSLog(@"Get Net data success!");
        }
    }];
    
    // step3. 发动task
      [dataTask resume];

    下面可以看下AF如何实现这三个步骤的:

    step1:实现生成Sesstion

    核心属性

    /**
     The managed session.
     */
    @property (readonly, nonatomic, strong) NSURLSession *session;
    
    /**
     The operation queue on which delegate callbacks are run.
     */
    @property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
    
    /**
     Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`.
    
     @warning `responseSerializer` must not be `nil`.
     */
    @property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
    
    ///-------------------------------
    /// @name Managing Security Policy
    ///-------------------------------
    
    /**
     The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
     */
    @property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
    
    #if !TARGET_OS_WATCH
    ///--------------------------------------
    /// @name Monitoring Network Reachability
    ///--------------------------------------
    
    /**
     The network reachability manager. `AFURLSessionManager` uses the `sharedManager` by default.
     */
    @property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
    #endif
    
    ///----------------------------
    /// @name Getting Session Tasks
    ///----------------------------
    
    /**
     The data, upload, and download tasks currently run by the managed session.
     */
    @property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
    
    /**
     The data tasks currently run by the managed session.
     */
    @property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
    
    /**
     The upload tasks currently run by the managed session.
     */
    @property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
    
    /**
     The download tasks currently run by the managed session.
     */
    @property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
    
    ///-------------------------------
    /// @name Managing Callback Queues
    ///-------------------------------
    
    /**
     The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
     */
    @property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
    
    /**
     The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
     */
    @property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

    核心方法解析

    initWithSesstionConfiguration

     (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
        self = [super init];
        if (!self) {
            return nil;
        }
        // =============== 设置NSURLSession ===============
        // 若configuration为nil,则采用默认defaultSessionConfiguration
    
        if (!configuration) {
            configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        }
    
        self.sessionConfiguration = configuration;
        // session 的delegate callback queue, 最大并发为1 
        self.operationQueue = [[NSOperationQueue alloc] init];
        self.operationQueue.maxConcurrentOperationCount = 1;
        // 初始化所管理的session
        self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    
    // =============== 设置response 数据序列化 ===============
        self.responseSerializer = [AFJSONResponseSerializer serializer];
    
    // =============== 设置网络安全策略 ===============
        self.securityPolicy = [AFSecurityPolicy defaultPolicy];
    
    // =============== 设置网络状态监控Manager(注意这里是一个全局单例实现) ===============
    #if !TARGET_OS_WATCH
        self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
    #endif
    // =============== 设置存储NSURL task与AFURLSessionManagerTaskDelegate的词典(重点,在AFNet中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate 来做task的delegate事件处理) ===============
        self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    
    // =============== 设置AFURLSessionManagerTaskDelegate 词典的锁,确保词典在多线程访问时的线程安全===============
        self.lock = [[NSLock alloc] init];
        self.lock.name = AFURLSessionManagerLockName;
    
    
    // =============== 为所管理的session的所有task设置完成块(这里不是很明白,既然是初始化函数,那么应该没有任何task在运行才是,怎么需要在这里设置完成块呢???)===============
        [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
            for (NSURLSessionDataTask *task in dataTasks) {
                [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
            }
    
            for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
                [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
            }
    
            for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
                [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
            }
        }];
     // =============== 返回初始化好的self ===============
        return self;
    }

    总结:1.初始化sesstion,opretion,安全策略,网络可达性,序列化/反序列化,data数组,downLoadData数组,upLoadData数组

                2.进入了sesstion的sesstionWithConfiguration的方法里面,传入delegate

    Setp2:生成Task

    - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                                   uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                                 downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {
    
        __block NSURLSessionDataTask *dataTask = nil;
        url_session_manager_create_task_safely(^{
            dataTask = [self.session dataTaskWithRequest:request];
        });
    
        [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
    
        return dataTask;
    }

    总结:1.dataTaskWithRequest建立task

              2.addDelegatForDataTask建立每一个delegate管理每个task

    - (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
                    uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
                  downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                 completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
    {
    // 创建AFURLSessionManagerTaskDelegate对象 AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init]; // 设置AF delegate的完成块为用户传入的完成块 delegate.completionHandler = completionHandler; // 设置dataTask的taskDescription dataTask.taskDescription = self.taskDescriptionForSessionTasks; // 设置AF delegate的上传进度,下载进度块。 delegate.uploadProgressBlock = uploadProgressBlock; delegate.downloadProgressBlock = downloadProgressBlock; // AFURLSessionManagerTaskDelegate与AFURLSessionManager建立相互关系 delegate.manager = self; // ***** 将AF delegate对象与 dataTask建立关系 [self setDelegate:delegate forTask:dataTask]; }
    - (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
                forTask:(NSURLSessionTask *)task
    {
        NSParameterAssert(task);
        NSParameterAssert(delegate);
    // 加锁,确保词典的线程安全
        [self.lock lock];
      // 将AF delegate放入以taskIdentifier标记的词典中(同一个NSURLSession中的taskIdentifier是唯一的)
           self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
     // 为AF delegate 设置task 的progress监听
        [delegate setupProgressForTask:task];
        [self addNotificationObserverForTask:task];
    // 词典操作完毕,解锁
        [self.lock unlock];
    }

    总结:1.初始化dataDlegate 2.建立block对应delegate的关系 3.建立task和delegate的对应关系

    Setp3.delegate之间的传递

    - (void)URLSession:(NSURLSession *)session
                  task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {
        // step1. 应交由AF task delegate处理的事件,取出对应AF task delegate,
        AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
    
        // delegate may be nil when completing a task in the background
        if (delegate) {
            // step2. 将事件交由AF task delegate处理
            [delegate URLSession:session task:task didCompleteWithError:error];
            // NOTE: 此处是session task最终的回调函数,task不会再返回任何信息。因此删除对应的AF task delegate
            [self removeDelegateForTask:task];
        }
        // step3. 若有对应的user block,则调用之
        if (self.taskDidComplete) {
            self.taskDidComplete(session, task, error);
        }
    }

    1.获取对应task的delegate,delegateForTask

    2.调用AF的delegate的对应的complete方法,传给了AFD

    3.判断,如果有block,设置block回调

    AFNetworkingSesstionDelegate

    @interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
    @property (nonatomic, weak) AFURLSessionManager *manager;
    @property (nonatomic, strong) NSMutableData *mutableData; // 保存服务器返回的数据
    @property (nonatomic, strong) NSProgress *uploadProgress; // 上传进度
    @property (nonatomic, strong) NSProgress *downloadProgress; // 下载进度
    @property (nonatomic, copy) NSURL *downloadFileURL; // 下载文件目的存储地址
    @property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; 
    @property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
    @property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
    @property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
    @end

    编者寄语,AFM对sesstionManager的封装,首先是基于实现几个步骤:1.初始化sesstionManager 2.初始化Task 3.回调的传递。

                     AFM在InitConfigution里面初始化了sesstion和相关的其它属性,完成了第一个问题。

                     AFM在dataTask方法里面初始化了 sesstion的dataTask,并且为每个dataTask分配了一个delegate

                    AFM在setdelegate里面将sesstion的回调传递给AF,如果有回调,使用delegatForTask方法,获取AF的delegate,如果有Block,赋值给Block

                   为什么不在Managter方法里面直接设置delelgate获取Bblock呢,而使用了中间层的AFD

              

  • 相关阅读:
    线段树
    2016.9.4
    使用CSS代码修改博客模板
    爬虫
    PHP初学[DAY2]
    2016.8.23
    一个自动设置游戏房间的脚本
    可逆矩阵生成
    #2284. 接水果(fruit)
    #3762. 有趣的数(number)
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/8097222.html
Copyright © 2020-2023  润新知