美文网首页
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 使用中遇到的坑,循环引用

    最近在写一个 SDK ,用到了 AFNetwork,其中有一段代码如下: 本以为没问题,结果每次使用才发现,回调中...

  • timer中的那些坑

    引言 我们在使用timer的时候多多少少都遇到过一些坑,今天就来说说timer使用中的那些坑 1.循环引用导致的内...

  • iOS开发中使用block也不一定要进行弱引用(使用weakSe

    在开发中我们会经常使用到block,而使用block会经常遇到循环引用的问题,为了解决循环引用的问题我们需要使用w...

  • iOS中block详解 weakSelf , strongSel

    在block中避免循环引用 我们知道,在使用block的时候,为了避免产生循环引用,通常需要使用weakSelf和...

  • block N连问

    Block 与 循环引用 1、 在所有的Block中,使用self 都会引起循环引用吗? 答:不一定.循环引用的原...

  • 我是如何实现自释放timer的

    引言 我们都知道timer在使用的时候有很多坑,比如强引用target导致循环引用,甚至内存泄露问的,timer触...

  • block-循环引用

    block的循环引用,在日常开发中,我们常常遇到,但是可能部分新人还不太了解为何会循环引用,到底是如何循环引用理解...

  • iOS开发 使用NSUInteger时遇到的坑

    踩坑场景 今天在使用NSUInteger的时候,遇到了一个坑,代码如下: 运行以上代码后,for循环会无限循环。 ...

  • swift学习笔记五

    一、循环引用 1.swift提供两种方法来解决你在使用类的属性的时候所遇到的循环引用的问题:弱引用[weak se...

  • Swift循环引用的解决方案

    解决实例之间的循环强引用,Swift 提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题:弱引用(we...

网友评论

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

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