网络完成块、递归和 ARC 保留周期



这是一个棘手的问题,答案可能对包括我在内的许多网络学徒有用。

关于上下文的一些背景信息:

  • 假设您要从在线服务下载数据
  • 您希望异步执行此操作
  • 您想一次进行一次下载
  • ,然后在完成前一次下载后再进行一次下载。

一种巧妙的方法是使用递归。你可以想出的常见实现的问题是保留周期,在网络完成块和自身之间。这可以使用弱自我引用指针来解决。

但是,递归调用的保留周期呢?

我们已经实现了一个递归堆栈,自指向一个下载管理类,如下所示:

-(void)startNetworkDownloadForObjectAtIndex:(int) anIndex
{
    __typeof__(self) __weak weakSelf = self;
    NSURL *urlForObjectAtIndex = [SomeClass URLforIndex:anIndex];
    [self.downloadManager getResourceAtURL:urlForObjectAtIndex success:^(AFHTTPRequestOperation *operation, id responseObject) {
                               if (indexOfObjectToDownload < weakself.totalNumberOfObjectsToDownload) [weakSelf startNetworkDownloadForObjectAtIndex:indexOfObjectToDownload+1];
                               else [weakSelf startDOwnloadTimer]; 
                            }
                            failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                // response code is in operation.response.statusCode
                                [weakSelf handleNetworkError:error];
                            }];
}

-(void)handleNetworkError:error
{
     // Do some error handling
     [self startNetworkDownloadForObjectAtIndex:self.lastUnsentObjectIndex];
 }
-(void)startDownloadTimer
{
     if (self.syncEngineTimer) [self.syncEngineTimer invalidate];
     self.syncEngineTimer = [NSTimer scheduledTimerWithTimeInterval:kSyncTimeInterval
                                                        target:self
                                                    selector:@selector(restartNetworkDownload)
                                                      userInfo:nil
                                                       repeats:NO];
}
-(void)restartNetworkDownload
{
      // do some fancy calculations / etc to manage your download
     int anIndex = theResultOfYourCalculation;
     [self startNetworkDownloadForObjectAtIndex:anIndex];
}

好的,这是一个可能递归调用多个网络下载的示例(例如,获取 100 张闪烁图片(,并尝试在 1 小时后获取新图片。请原谅任何编码错别字。

我们正在 iOS 5.0 以上的 iOS 设备的 ARC 下运行它

在使用 self.downloadManager 保留对成功和失败完成块的引用时,我们显然通过使用弱 Self 引用指针打破了第一级保留周期。这一切都很好,在乐器中很顺利。

现在,在查看工具中的分配时,我们为多个下载启动下载操作。仪器显示无泄漏。但是,当反刍地保存堆时,您可以看到它缓慢增长。

检查分配并查看调用堆栈,看起来该块肯定通过使用startDownloadTimer 保留对自身的引用

任何关于可能的原因和解决方案的解释将不胜感激:)

计时器保留其目标(self (。

尝试以下问题的解决方案: 对 NSTimer 目标的弱引用以防止保留周期

或者使用dispatch_after而不是计时器。

最新更新