AFNetworking作为开发者网络库的标配,发展了很多版本,我是从2.0开始使用,再到3.0的重大改版,虽然没有细致看过源码,但是多次调试,已经对源码比较熟悉。
来挑战~
也是真的是“只是在人群中偷偷看了你一眼,再也不能忘掉你容颜”,下面这段AFNetworking2时期(2015~2016年)的代码让我一直记忆犹新,大家来找茬,看看代码有没有问题 (重点标注的那段if else ):
- (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(), ^{
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
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
}
希望大家先看下上面代码中if else逻辑,分析下有啥问题没?
初印象~
那时候真的是匆匆一瞥,闪念就是开源代码这位大神也会犯这么简单的错误? if和else中的 if (failure)这段逻辑明显是重复啊! 可以直接删掉一段,我们把它摘出来:
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;
// WTF!!! 下面这个if 不是上面if的重复吗 ???
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 (failure)同样的逻辑,但是第二个 if (failure)前面有这样一句代码:
id responseObject = self.responseObject;
只是一个赋值,会对 if (failure)有什么影响吗?
但真的只是一个赋值吗?
我们习惯性思维通常是这样:取出self的属性responseObject的值,赋值给局部变量responseObject。通常情况这样理解没问题,但是这是建立在我们大多数情况不会重写属性的setter和getter方法! 如果这里重写了responseObject属性的setter和getter方法呢? 点击self.responseObject的 “jump to definition” 后我终于参透了:
- (id)responseObject
{
[self.lock lock];
if (!_responseObject && [self isFinished] && !self.error) {
NSError *error = nil;
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
if (error) {
self.responseSerializationError = error;
}
}
[self.lock unlock];
return _responseObject;
}
可以看到在getter方法中,会对error再次赋予新的值,所以在 id responseObject = self.responseObject;后面的if中需要重新判断是否有error。
网友评论