块和内存泄漏

时间:2013-04-25 04:29:55

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

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

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);

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

3 个答案:

答案 0 :(得分: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. 上添加了retain
  3. downloadQueue开始执行阻止// +1
  4. callerQueue在self // +2
  5. 上添加了retain
  6. downloadQueue发布它保留// +1
  7. callerQueue开始执行内部块// +1
  8. callerQueue释放它的保留。 // + 0
  9. 因此,在任何时候,都会有自己的retainCount。顺便说一句,您甚至可以随时查看保留计数-[NSObject retainCount]

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

答案 1 :(得分:0)

首先会发生什么:内部块无法从方法中捕获self,因为在创建内部块时该方法可能会很久。因此,它从外部块捕获自我。这意味着“self”用作外部块中的变量,这意味着外部块捕获它。因此,当执行内部块时,self将存在。

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

_weak WhatEverType* weakSelf = self; 

在您的方法中,

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

在内部块中。结果:内部块不保持“自我”保留;自我不会因为它被用在街区而留在身边。如果它被dealloc'ed,weakSelf设置为nil,你检查一下。你可以把它扔掉,而不是存储图像。但是一旦strongSelf被设置为非零指针,你就知道它会一直停留在块的末尾。

答案 2 :(得分:-2)

最好不要将自己保留在队列中或阻止。使用以下命令使“self”成为非保留对象:

__unsafe_unretained ViewController *tempController = self;

然后将每个对象调用为tempController.imageView.image,依此类推。