1

我正在使用以下代码异步下载图像并将其设置为图像视图。块和内存泄漏

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然后再转回到callerQueue之间自行释放?

+0

不,这样会好的。自我将由downloadQueue保留,然后由callerQueue保留,然后由downloadQueue发布,然后由callerQueue发布(最有可能以该顺序发布)。 – borrrden 2013-04-25 04:46:55

+0

我没有使用ARC。 – 2013-04-25 04:48:20

+0

@eddardstark如果你不使用ARC,那么你不必担心这样的事情。只有当你指示他们这样做时才会保留和释放。 – 2013-04-25 04:49:17

回答

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

因此,在任何时候,都会有自我保留计数。顺便说一句,你甚至可以随时用-[NSObject retainCount]检查保留计数。

作为一个附注,为什么不使用dispatch_get_main_queue()而不是保存callerQueue。你应该从来没有在任何其他线程上做UI操作。如果您的函数是从其他任何线程调用的,则这更安全。

+1

'retainCount'没用,不要打电话给它。好的答案,否则。 – bbum 2013-04-26 13:24:44

+0

@bbum在意解释为什么'retainCount'没用?它是一个很好的调试工具IMO。 – Mar0ux 2013-04-26 13:25:41

+0

当然;不反映autorelease,不反映线程所有权,实现细节可能会使其与预期的大不相同,等等......详情请见:http://www.friday.com/bbum/2011/12/18/retaincount-是无用/ – bbum 2013-04-26 16:21:35

-2

它总是最好不要保持自己在队列或块中。使用以下方法来使“自我”非保留对象:

__unsafe_unretained ViewController *tempController = self; 

,然后调用每一个对象作为tempController.imageView.image等。

0

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

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

_weak WhatEverType* weakSelf = self; 
在你的方法

,并

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

在内部块。结果:内部块不保留“自我”保留;自我不会因为它在块中被使用而停留在周围。如果它被释放,weakSelf被设置为零,然后你检查它。而不是存储图像,你只需把它扔掉。但是一旦strongSelf被设置为非零指针,就会知道它将一直保持到块的末尾。