自動釋放池
AutoreleasePool的實現(xiàn)原理是怎么樣的?
AutoreleasePool是以棧為結(jié)點,通過雙向鏈表的形式組合而成的數(shù)據(jù)結(jié)構(gòu)。編譯器會將@autoreleasepool{}改寫,如下 圖。實際objc_autoreleasePoolPop函數(shù)在內(nèi)部做了pop操作,批量將autoreleasepool中的所有的對象都會做一次release操作。
編譯器改寫@autoreleasepool{}
下面對上面的主要函數(shù)進行一個簡單的說明
AutoreleasePool的結(jié)構(gòu)
1)是以棧為結(jié)點通過雙向鏈表的形式組合而成
2)是和線程一一對應的

[obj autorelease]的實現(xiàn)(對象加入自動釋放池)
先判斷當前next指針是否指向棧頂,如果不是直接加入;如果是,則增加一個棧結(jié)點到鏈表上,在新的棧添加對象;移動next指針
AutoreleasePoolPage::push實現(xiàn)流程(釋放池多層嵌套)
插入哨兵對象

AutoreleasePoolPage::pop實現(xiàn)流程(與push相反)
? ??根據(jù)傳入的哨兵對象找到對應的位置
? ??給上次push操作之后添加的對象依次添加release消息
? ??回退next指針到正確的位置
AutoreleasePool為何可以嵌套使用?
多次插入哨兵對象,也就是對一個新的releasePool的創(chuàng)建,如果當前棧沒有滿,則不需要創(chuàng)建新的page,如果滿了,新增一個棧節(jié)點
下面這個圖中,array對象在什么時候釋放呢?

在當次runloop將要結(jié)束的時候調(diào)用AutoreleasePoolPage:pop(),對array對象執(zhí)行release操作。
AutoreleasePool的使用場景?
在for循環(huán)中,alloc圖片數(shù)據(jù)等內(nèi)存消耗較大的場景手動插入autoreleasePool,每一次for循環(huán)都進行一次內(nèi)存的釋放,降低內(nèi)存消耗。
常見的循環(huán)引用以及破除方法:
代理(delegate)
block
NSTimer
大環(huán)引用
如何破除循環(huán)引用?
__weak
__block
__unsafe_unretained(與weak等效)
__block在ARC和MRC條件下的區(qū)別
MRC下,__block修飾對象不會增加其引用計數(shù),避免了循環(huán)引用
ARC下,__block修飾對象會被強引用,無法避免,需手動破環(huán)
NSTimer? 循環(huán)引用解決

如果沒有其他處理,只是單純地在dealloc中寫定時器的銷毀方法,在退出當前控制器后,由于定時器的循環(huán)引用問題導致當前類沒有釋放銷毀,也就不會走dealloc 方法,所以退出控制器后定時器仍然在執(zhí)行。
1)在退出界面時手動調(diào)用定時器銷毀的方法。
2)引入中間者

3) 高級中間者
此時我們需要借助一個虛基類NSProxy,(NSProxy其主要用來消息轉(zhuǎn)發(fā)的處理)



4、帶block的timer
在我們創(chuàng)建timer的時候,蘋果也意識到NSTimer的api是存在一定問題的,所以在iOS10.0之后提供了一種block的方法來去解決NSTimer的循環(huán)引用的問題.
