Block
是在棧上生成的,因此通常使用copy
方法把Block
複製到堆上,避免Block
被馬上釋放。spa
Block
會對內部的變量造成強引用,而若是同時該變量又持有這個Block
,就會致使循環引用而沒法釋放,從而致使內存泄露。code
最多見的就是self
持有Block
,而又在Block
內部調用self
的方法或屬性,那self
和Block
就會造成循環引用而沒法釋放。因爲咱們習慣在dealloc
中釋放對象,可是即便在dealloc
中將Block
釋放也沒用,由於self
的dealloc
根本不會跑進去。好比:對象
1 self.MyBlock = ^void(){ 2 3 [self doSomething]; 4 };
其實,最簡單的解決方法就是在self
的某個非dealloc
方法中將Block
主動釋放,並在須要釋放self
以前調用這個方法,這樣纔能有效的解除引用。可是這種方法使用起來比較麻煩,並且很容易忘記調用。blog
因此咱們通常是在Block
中使用弱引用的self
。下面分別介紹ARC
和MRC
中在Block
中使用弱引用self
的方法。內存
1 __weak typeof(self) weakSelf = self; 2 3 self.MyBlock = ^void(){ 4 5 __strong typeof(self) strongSelf = weakSelf; 6 7 [strongSelf doSomething]; 8 };
這樣作的好處是沒必要在Block
直接使用self
,這樣就不會對self
進行強引用,只要self
須要釋放,self
就會自動釋放,Block
也會自動釋放。在ARC
中,進入Block
前,須要使用__weak
對self
進行弱引用,並在Block
中使用__strong
對weakSelf
進行強引用。開發
這樣作的另外一個好處是,在ARC
中使用__weak
以後,若是self
在某個地方被釋放了,那weakSelf
也會被自動置爲nil
,這樣即便在Block
中使用weakSelf
,也不會訪問錯誤。get
而在Block
中使用__strong
則是爲了不在使用Block
的過程當中self
被釋放致使訪問出錯。class
1 __block typeof(self) blockSelf = self; 2 3 self.MyBlock = ^void(){ 4 5 if (!malloc_zone_from_ptr(blockSelf)) 6 return; 7 8 __strong typeof(self) strongSelf = blockSelf; 9 10 [strongSelf doSomething]; 11 };
其實,MRC
的基本思路和ARC
是同樣的。有兩處不一樣:變量
在MRC
中使用__block
而不是__weak
進行弱引用,由於在ARC
中使用__block
會對該對象進行強引用。循環
在MRC
的Block
中使用malloc_zone_from_ptr()
方法判斷blockSelf
是否已經被釋放,由於MRC
不會對已釋放的對象自動置爲nil
。
可見,不管是MRC
仍是ARC
,解決方法都是相似的。雖然Block
的使用增長了簡潔性和便利性,但使用Block
的過程當中也要時刻注意避免內存泄露。
How Do I Declare A Block in Objective-C? 總結了聲明Block
的幾種格式,在開發過程當中能夠參考使用。