復(fù)習(xí)下block和內(nèi)存相關(guān)的知識
Stack(棧) & Heap(堆)
棧的讀寫速度比堆快放棒,這就解釋了為什么方法中的變量會分配到椂焉空間井氢。
一般而言腾务,代碼中被{}
包含的區(qū)間變量都存儲在棧中虹脯,當(dāng)這一區(qū)間執(zhí)行結(jié)束的時候驴娃,所有區(qū)間變量都會被系統(tǒng)自動釋放,所以棧中的對象無法被外界retain
循集。
堆用來存儲對象Object
唇敞,我們需要自己釋放堆中的對象(ARC只是讓編譯器幫我們做了而已)。
內(nèi)存泄漏發(fā)生在堆上咒彤,當(dāng)堆上分配的內(nèi)存空間沒有被顯示釋放的時候疆柔,泄漏就發(fā)生了。
不同的應(yīng)用有不同的堆空間蔼紧,不同的線程有不同的棧婆硬,同一應(yīng)用中的不同線程通過堆來共享數(shù)據(jù)。
Block
Block是唯一分配在棧上的對象奸例。
棧中存儲的內(nèi)容一般是一些定長的變量彬犯,比如int
,bool
查吊,對象地址等谐区。Block也是確定長度的,一個Block被創(chuàng)建之后就無法再修改逻卖。
當(dāng)Block所在的區(qū)間執(zhí)行結(jié)束宋列,它就會被釋放,我們知道棧中的對象無法被retain
评也,那么怎么傳遞Block呢炼杖?
答案是將Block拷貝到堆上。
這就是為什么我們經(jīng)常用copy
來修飾Block變量
@property (copy, nonatomic) void (^block) ();
當(dāng)對Block第一次使用copy
的時候盗迟,Block會被拷貝到堆上坤邪;對其后續(xù)的copy
并不會拷貝多次,只會增加引用計數(shù)罚缕。
用strong
修飾Block并不會拷貝艇纺,如果Block是存儲在棧上的,這個strong對象可能會成為一個野指針。
Block循環(huán)引用
常見的Block循環(huán)應(yīng)用便是在Block代碼區(qū)間中持有了self
黔衡。
這里需要注意的是:如果Block只是在棧上蚓聘,當(dāng)它執(zhí)行結(jié)束之后系統(tǒng)會自動釋放其內(nèi)部變量,所以并不會發(fā)生內(nèi)存泄漏盟劫。
不過我們遇到的Block經(jīng)常會被傳遞夜牡,也就是存儲在堆上,這時候就需要用weak-strong-dance來處理了捞高。
__block
Block存儲在棧上氯材,所以Block會將它用到的所有外部變量進(jìn)行拷貝,這也就是為什么在Block中修改外部變量的值不會生效(修改指針指向的內(nèi)容另當(dāng)別論)硝岗。
__block
做的事情就是如果這個變量在Block中被捕獲氢哮,那么就將這個變量拷貝到堆上,這樣一來就可以修改了型檀。