最近在写一个 SDK ,用到了 AFNetwork,其中有一段代码如下:
...
@property(nonatomic,strong)AFHTTPSessionManager *request;
....
-(void)excute{
...
@weakify(self);
[self.request POST:self.api.APIPath
parameters:self.api.params
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
@strongify(self);
[self handelResponseComplete:responseObject];
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
@strongify(self);
[self handelResponseError:error];
}];
...
}
本以为没问题,结果每次使用才发现,回调中的 self 已经被释放了.想了一下,还真是,由于这个类在使用中是被作为临时变量来使用的,生命周期一结束,没有强引用,就完蛋了.由于想要先写一点功能,就干脆直接把@strongify(self);
去掉了,直接上,这次倒不会被释放,倒是老觉得会循环引用.
始终还是不放心,在-dealoc
方法中加上打印输出,看看代码.
突然发现,居然会正常释放!
这还了得,赶紧看看是不是哪里弄错了.找了半天好像也没找到我哪里写错了,还是看看 AFNetwork 源代码吧.
,先来看看这个post
方法
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
[dataTask resume];
return dataTask;
}
再一路跟进,到了AFURLSessionManager
的这个方法
- (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 *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
这里创建了一个代理类,然后把 block 保存在代理类中,而代理类本身通过这个方法
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
存放在了一个字典属性中.
来捋一捋
self(我自己代码) -持有> requst(AFHTTPSessionManager)-持有>mutableTaskDelegatesKeyedByTaskIdentifier(字典)-持有>delegate-持有>block-持有>self(我自己代码中的)
好大一个环,不过这不还是一个环吗?
不理解.
又来打断点调试
看到一个这个代码
有一句[self removeDelegateForTask:task];
这不刚刚和那个-setDelegate:forTask:
对应吗?去看看代码
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
[self.lock lock];
[delegate cleanUpProgressForTask:task];
[self removeNotificationObserverForTask:task];
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
[self.lock unlock];
}
果然, AFNetwork 在请求结束后会自动释放掉 delegate,打破那个环,所以循环引用也就不存在了.