关于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响应对象。
.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的父类当中它并没有做什么,就是给NSOperation中CompletionBlock赋值,为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); } }); };