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被設置爲非零指針,就會知道它將一直保持到塊的末尾。