ios - 网络完成 block 、递归和 ARC 保留循环

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

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

上下文的一些背景信息:

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

一种简洁的方法是使用递归。 您可以想到的常见实现的问题是网络完成 block 和自身之间的保留周期。这可以使用 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 保持对成功和失败完成 block 的引用时,我们显然通过使用 weakSelf 引用指针打破了第一级保留循环。这一切都很好,并且在仪器中进展顺利。

现在,在 Instruments 中查看分配时,我们启动了一个下载操作以进行多次下载。 仪器显示没有泄漏。 但是当定期保存堆时,您可以看到它在缓慢增长。

检查分配并查看调用堆栈,看起来该 block 确实通过使用 startDownloadTimer 保持对自身的引用

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

最佳答案

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

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

或者使用dispatch_after代替定时器。

关于ios - 网络完成 block 、递归和 ARC 保留循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19134136/

相关文章:

ios - 在 Button iOS 的中心对齐按钮

objective-c - 我们如何创建带注释的 PDF

python - 如何测试 python 中的递归函数不会永远持续下去?

使用递归计算更大数组中子数组的出现次数

ios - 通过 POST 登录后如何到达下一页

objective-c - 使用 UINavigationController View 进行内存管理

ios - 如何在 iOS iPad 模拟器中调出 iOS 多任务栏

ios - 添加 subview 并以编程方式使用约束定位它

javascript - 如何递归调用异步函数?

objective-c - 在 UITableView 中自定义索​​引/部分栏的字体/背景颜色