美文网首页
AFNetwork 使用中遇到的坑,循环引用

AFNetwork 使用中遇到的坑,循环引用

作者: yww | 来源:发表于2016-01-29 12:10 被阅读2007次

    最近在写一个 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(我自己代码中的)
    好大一个环,不过这不还是一个环吗?
    不理解.
    又来打断点调试

    调试

    看到一个这个代码

    -URLSession:task:didCompleteWithError:

    有一句[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,打破那个环,所以循环引用也就不存在了.

    相关文章

      网友评论

          本文标题:AFNetwork 使用中遇到的坑,循环引用

          本文链接:https://www.haomeiwen.com/subject/jlujkttx.html