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

时间:2013-10-02 09:47:32

标签: ios objective-c recursion objective-c-blocks self

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

有关背景的一些背景信息:

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

这样做的一个巧妙方法是使用递归。 您可以提出的常见实现的问题是网络完成块和自身之间的保留周期。这可以使用weakSelf参考指针来解决。

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

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

-(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小时后获得新的网络。 请原谅任何编码错字。

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

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

现在,在查看Instruments中的分配时,我们会启动下载操作以进行多次下载。 仪器没有泄漏。 但是当重新保存堆时,你可以看到它慢慢增长。

检查分配并查看调用堆栈,看起来该块通过使用startDownloadTimer来保持对self的引用

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

1 个答案:

答案 0 :(得分:1)

您的计时器保留其目标(self)。

尝试此问题的解决方案:Weak Reference to NSTimer Target To Prevent Retain Cycle

或使用dispatch_after代替计时器。