【问题标题】:Blocks and memory leaks块和内存泄漏
【发布时间】:2013-04-25 04:29:54
【问题描述】:

我正在使用以下代码异步下载图像并将其设置为图像视图。

dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("com.myapp.processsmagequeue", NULL);
dispatch_async(downloadQueue, ^{
        NSData * imageData = [NSData dataWithContentsOfURL:url];

           dispatch_async(callerQueue, ^{

                self.imageView.image = [UIImage imageWithData:imageData];
                [self.imageActivityIndicatorView setHidden:YES];
                [self.imageView setHidden:NO];
            });
    });
dispatch_release(downloadQueue);

我知道这些块会自动保留它们引用的所有值,然后释放它们。但是 self 可以在移动到 downloadQueue 和传输回 callerQueue 之间释放吗?

【问题讨论】:

  • 不,这样就可以了。 self 将由 downloadQueue 保留,然后由 callerQueue 保留,然后由 downloadQueue 释放,然后由 callerQueue 释放(很可能按此顺序)。
  • @eddardstark 如果您不使用 ARC,那么您不必担心这样的事情。保留和释放只有在您指示他们这样做时才会发生。
  • 这样的事情怎么样..无论什么原因,下载队列都会卡住大约 5 分钟。并且在那个自我之中被释放。现在在这种情况下..在转移到呼叫者队列或后记之前下载队列是否会释放自我?这就是困扰我的地方。
  • @H2CO3 如果我没记错的话,ARC不会处理任何派送和CG案件。
  • @thoughtbreaker 但是这里没有 ARC!阅读第二条评论...

标签: ios objective-c memory-management memory-leaks objective-c-blocks


【解决方案1】:

这应该没问题。

dispatch_async(downloadQueue, ^{ // --> downloadQueue will add a retain on self when it's created
           dispatch_async(callerQueue, ^{ // --> callerQueue will add a retain on self when it's created
                 ...
            }); // --> callerQueue will release it's retain when it gets dealloced just after returning from here
    // --> downloadQueue will release it's retain when it gets dealloced just after returning from here
    });

下面是它的执行方式:

  1. downloadQueue 为自身添加保留 // +1
  2. downloadQueue 开始执行块 // +1
  3. callerQueue 在自身上添加保留 // +2
  4. downloadQueue 释放它的保留 // +1
  5. callerQueue 开始执行内部块 // +1
  6. callerQueue 释放它的保留。 // +0

所以,在任何时候,self 都会有一个 retainCount。顺便说一句,您甚至可以随时使用-[NSObject retainCount] 检查保留计数。

作为旁注,为什么不使用dispatch_get_main_queue() 而不是保存 callerQueue。您应该从不在任何其他线程上执行 UI 操作。万一您的函数从任何其他线程调用,这会更安全。

【讨论】:

  • retainCount 没用,别打电话了。否则很好回答。
  • @bbum 解释一下为什么retainCount 没用?它是一个很好的调试工具 IMO。
  • 当然;不反映自动释放,不反映线程所有权,实现细节可能会与预期大相径庭,等等......这里的详细信息:friday.com/bbum/2011/12/18/retaincount-is-useless
【解决方案2】:

首先会发生什么:内部块无法从方法中捕获自身,因为在创建内部块时该方法可能早已不复存在。因此,它从外部块捕获自我。这意味着“self”被用作外部块中的变量,这意味着外部块捕获它。如所写,执行内部块时, self 将在那里。

另一方面,您可能不希望这样。您可能不想让该视图保持活动状态,以便将下载的图像存储在那里。在这种情况下,你写

_weak WhatEverType* weakSelf = self; 

在你的方法中,并且

WhatEverType* strongSelf = weakSelf;
if (strongSelf != nil)
{
}

在内部块中。结果:那个内部块没有保留“自我”; self 不会仅仅因为它在块中使用而留下。如果它被释放,weakSelf 被设置为 nil,你检查一下。您无需存储图像,而是将其丢弃。但是一旦 strongSelf 被设置为一个非 nil 指针,你就知道它会一直停留在块的末尾。

【讨论】:

    【解决方案3】:

    最好不要将 self 留在队列中或阻塞中。使用以下方法使“自我”成为非保留对象:

    __unsafe_unretained ViewController *tempController = self;
    

    然后将每个对象称为 tempController.imageView.image 等等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 2010-12-02
      • 2013-11-08
      • 2016-05-03
      相关资源
      最近更新 更多