2014-09-03 97 views
1

我有一個關於objc塊的問題。如果你想在塊中使用自己,你應該減弱它並在塊中再次強化它,這樣你就不會陷入保留週期。在我的情況下,我也想寫一個塊的存在類的屬性。現在我有點困惑,如果這是有道理的,如果我以後可以訪問此屬性,或者如果我完全失去對此屬性的引用。Objective-C塊的生命週期和保留週期

這裏是我的代碼示例:

所有的
__weak typeof(self)weakSelf = self; 
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject) 
     { 
      __strong typeof(weakSelf)strongSelf = weakSelf; 

      if (strongSelf) { 
       strongSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType]; 
       [strongSelf postSuccessNotification:strongSelf->_response]; 
      } 
     }; 

首先使此代碼完全感覺或者是有什麼優化?

有人可能會再次解釋在objc內部發生了什麼。我現在閱讀了幾篇文章,而且我比以前更關心保留週期的困惑。據我所知,一個塊是一個對象,如果它捕獲變量,則變量被內部拷貝並默認聲明爲const,只要你不使用__block聲明(關於全局變量中的生命屬性呢?)。我仍然沒有完全弄清楚塊的生命週期是什麼,爲什麼指針可能會晃來晃去,因爲整個塊對象及其內容在完成時應該被釋放。如果有人有時間,我會欣賞一個書呆子和詳細的答案或鏈接到一個很好的閱讀資源! :)

在此先感謝:)

回答

3

我想解釋3種方法來編寫塊。

第一:使用self

void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject) 
{ 
    self->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType]; 
    [weakSelf postSuccessNotification:self->_response]; 
}; 

handleRequestBlock保留self,如果self已擁有該塊的屬性,將有一個留住圈。該塊將保留self,直到您釋放塊。因此,如果在調用塊之後釋放塊(將塊設置爲零釋放它),則循環將不存在。

注意:大多數實現在調用它之後不會釋放該塊,因爲我們之後可能需要它,所以保留圈將始終存在。

二:使用weakself

__weak typeof(self)weakSelf = self; 
NSLog(@"%p", &weakSelf) ; 
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject) 
{ 
    NSLog(@"%p", &weakSelf) ; 
    weakSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType]; 
    [weakSelf postSuccessNotification:weakSelf->_response]; 
}; 

塊將不保留自我,如果是自實例被釋放,weakSelf是零。

更多關於這個例子:我添加兩行日誌來顯示:變量weakSelf的地址在塊範圍之外和塊範圍內是不同的。因爲weakSelf是一個本地堆棧並且變量爲__weak,所以使用具有相同值weakSelf的變量捕獲它,但不發送保留消息給它指示的實例,這裏是另一個具有不同地址的變量。

第三:僅在需要時才保留self

__weak typeof(self)weakSelf = self; 
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject) 
{ 
    __strong typeof(weakSelf)strongSelf = weakSelf; 

    if (strongSelf) { 
     strongSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType]; 
     [strongSelf postSuccessNotification:strongSelf->_response]; 
    } 
}; 

上有第二種方法有一個缺點:如果當塊正在執行的第一行代碼,執行這行代碼後,自不釋放,自我的情況下被釋放(因爲我們沒沒有保留它,它可能在其他線程上發送釋放方法,並且它將被釋放),在第二行代碼中,weakSelf爲零,所以會發生不好的事情,這取決於你的代碼的邏輯。

所以第三種方法解決了這個問題,它只在塊執行時保持自我,並在塊的末尾釋放自我(釋放意味着減少保留計數1)。

更多鏈接:

Working with blocks

A look inside blocks

How do i avoid caturing self in blocks...

+0

在我的代碼示例不會的我_original_自我參考伊娃_response得到函數的返回值,或者是分配到自我的原始實例的複製版本?仍嘗試獲取將對象複製/新創建的位置,並保留對原始對象的引用。 – slngr 2014-09-03 12:55:50

+0

@slngr這個[link](http://www.galloway.me.uk/2012/10/a-look-inside-blocks-episode-1/)有幫助嗎? – KudoCC 2014-09-04 01:59:40

+0

@slngr對不起,我不明白你的意思。你應該知道:在塊中使用'__weak'的變量將不會被髮送'retain'方法,你可以從我的例子2中推導出來。再一次,'__strong typeof(weakSelf)strongSelf'' strongSelf'只會在塊被調用時保留'self',而weakSelf'不是零。 – KudoCC 2014-09-04 02:39:00