AFNetWorking初探之AFHTTPRequestOperation(三)

关于AFHTTPRequestOperation 之前已经说说其使用方法,以及一些固定的包装初始化的操作,今天我们深入到setCompletionBlockWithSuccess看看它到底怎样的去回调,怎样的维护线程。首先贴出源码。

.h中的说明

/**
 Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed.

 This method should be overridden in subclasses in order to specify the response object passed into the success block.

 @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request.
 @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request.
 */
- (void)setCompletionBlockWithSuccess:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(nullable void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;


用一个block设置complerionblock 属性,成功还是失败的block都取决于完成时的请求码。如果“error”返回一个值,由于不能接受的状态码或者内容类型导致的,这时“failure”将被执行,其他情况“success”将被执行。

这个方法应该被子类覆盖,为了指定被传递进去的成功block响应对象。





.m中的实现

- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
    self.completionBlock = ^{
        if (self.completionGroup) {
            dispatch_group_enter(self.completionGroup);
        }

        dispatch_async(http_request_operation_processing_queue(), ^{
            if (self.error) {
                if (failure) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        failure(self, self.error);
                    });
                }
            } else {
                id responseObject = self.responseObject;
                if (self.error) {
                    if (failure) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            failure(self, self.error);
                        });
                    }
                } else {
                    if (success) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            success(self, responseObject);
                        });
                    }
                }
            }

            if (self.completionGroup) {
                dispatch_group_leave(self.completionGroup);
            }
        });
    };
#pragma clang diagnostic pop
}


首先看两个参数参数都是block类型的一个成功的block 一个失败的block。

      成功block将在请求成功的时候会调用里面的代码,可以看到他是一个没有返回值的block,里面有两个参数 AFHTTPResuestOperation *operation  id responseObject。失败block将在请求失败的时候调用,同样是一个block,其中也有两个参数AFHTTPResuestOperation *operation,NSError *error。

     源码当中第一行注释说道completionblock是在AFURLConnectionOperation当中被手动的从保留循环中杀掉。然后是一些忽略编译警告。

     我们看函数当中具体做了什么,分析结构,其实函数中只做了一件事,给一个叫completionBlock的属性赋值,看看他的定义,我们发现其实这个completionBlock的定义其实并不在AFHTTPRequestOperation当中包括其父类AFURLConnectionOperation当中也没有这个定义,其实这个completionBlock的定义在NSOperation当中。@property (nullable,copy)void (^completionBlock)(void)NS_AVAILABLE(10_6,4_0);这里苹果并没有给我们注释说明,不过从名字也应该知道他的作用。这里说一下self.completionBlock=... 根据苹果kvc机制我们知道,‘.’号调用其实是在调用这个属性的set方法,如果本类当中没有set方法会去父类中查找,所以这句话其实调用到了AFURLConnectionOperation当中的setComletionBlock:方法,代码如下:

- (void)setCompletionBlock:(void (^)(void))block {
    [self.lock lock];
    if (!block) {
        [super setCompletionBlock:nil];
    } else {
        __weak __typeof(self)weakSelf = self;
        [super setCompletionBlock:^ {
            __strong __typeof(weakSelf)strongSelf = weakSelf;  //这种写法在afnetworking当中经常出现,貌似是为了防止过早被回收,详细的笔者没有研究过,感兴趣的可以去看看。

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
            dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop

            dispatch_group_async(group, queue, ^{
                block();
            });

            dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
                [strongSelf setCompletionBlock:nil];
            });
        }];
    }
    [self.lock unlock];
}


从中仍然看到了self.lock这个我们在上一遍中已经说过了,他的初始化实在包装的时候已经完成了。 这个函数完成一件事:调用父类的setCompletionBlock方法(也就是给NSOperation中CompletionBlock赋值),在block中开辟新的线程执行我们在AFHTTPResuestOperation中写的block代码。下面的notify 是于上面__strong__typeof(weekSelf)...对应的为了内存管理。这里再说下上面的

 dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group()这句话是个静态函数实现代码如下

static dispatch_group_t url_request_operation_completion_group() {
    static dispatch_group_t af_url_request_operation_completion_group;
    static dispatch_once_t onceToken;//单例模式保证只执行一次
    dispatch_once(&onceToken, ^{
        af_url_request_operation_completion_group = dispatch_group_create();
    });

    return af_url_request_operation_completion_group;
}

以上说了这么多其实我们发现在AFHTTPResuestOperation的父类当中它并没有做什么,就是给NSOperationCompletionBlock赋值,为AFHTTPResuestOperation当中的block开辟线程,加入lock防止并发访问时导致错误,现在我们回到AFHTTPResuestOperation当中的block当中看看他做了什么

 self.completionBlock = ^{
        if (self.completionGroup) {//与下面的dispatch_group_leave相对应

            dispatch_group_enter(self.completionGroup);
        }

        dispatch_async(http_request_operation_processing_queue(), ^{
            if (self.error) {  //如果error存在
                if (failure) { //判断是否有failure block 如果有的执行下面代码  没有的话什么都没做
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(),<span style="font-family: Arial, Helvetica, sans-serif;">self.completionQueue ?: dispatch_get_main_queue(), ^{</span>
                        failure(self, self.error);
                    });//子线程中执行failure block,这里用到了?表达式  如果self.completionGroup存在就什么都不做 不存在就去赋值。
                 }
            } else { //如果error不存在执行下面代码

               id responseObject = self.responseObject;
               if (self.error) {//判断self中error是否为空 这里应该是始终不会存在的 可能跟线程有关这里又判断了一次
                  if (failure) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            failure(self, self.error);
                        });
                    }
                } else { //这里应该是始终都会做的
                   if (success) {//判断success block是否存在存在的话执行下面的代码
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            success(self, responseObject);
                        });//子线程中执行success bolck

                    }
                }
            }

            if (self.completionGroup) {
                dispatch_group_leave(self.completionGroup);
            }
        });
    };


你可能感兴趣的:(AFNetworking)