OC语言Block 续
OC語(yǔ)言 Block
轉(zhuǎn)載:http://blog.csdn.net/weidfyr/article/details/48138167
1.Block對(duì)象中的變量行為
結(jié)論:
在block代碼塊內(nèi)部可以訪問定義的全局變量,局部變量,靜態(tài)局部變量,但是訪問局部靜態(tài)變量時(shí)候是只讀的并且局部變量和在代碼塊中訪問到的不是同一個(gè)地址的變量,他們?cè)跀?shù)值上相等,互相似乎沒什么聯(lián)系。 因?yàn)榇a塊中使用到局部變量的時(shí)候,會(huì)將局部變量進(jìn)行const類型的copy,所以在代碼塊中訪問到的局部變量都是只讀的;靜態(tài)變量和全局變量都存放在靜態(tài)區(qū),在程序運(yùn)行過程中都存在,他們可以在不同的代碼塊中共享,不同代碼塊中訪問到的同一個(gè)全局變量,局部變量是同一塊內(nèi)存的數(shù)據(jù);對(duì)于普通局部變量在代碼塊中只讀,全局變量和靜態(tài)局部變量在代碼塊中可以讀寫。
在塊句法的主體中,除塊句法內(nèi)部的局部變量和形參之外,還包含塊句法當(dāng)前位置處可以訪問的變量;這些變量中包含外部變量也包含塊中可以訪問的局部變量。
代碼塊中訪問局部變量時(shí)候,局部變量會(huì)從棧內(nèi)存被const類型的copy一份到堆內(nèi)存中。
塊對(duì)象和函數(shù)指針的定義使用功能都差不多,塊對(duì)象的精髓之處就在于,在塊對(duì)象中可以訪問到上下文的變量,而函數(shù)指針不能。
2.塊對(duì)象的實(shí)例和生命周期
- 1)塊句法也可以寫在函數(shù)的外部,當(dāng)寫在函數(shù)外面時(shí)候,只是在靜態(tài)數(shù)據(jù)區(qū)分配一塊內(nèi)存給塊對(duì)象,這塊區(qū)域在程序執(zhí)行期間會(huì)一直存在。
- 2)塊句法寫在函數(shù)內(nèi)部的時(shí)候,塊對(duì)象和變量的生命周期和普通局部變量一樣,塊對(duì)象的內(nèi)存區(qū)域會(huì)在執(zhí)行包含塊對(duì)象的函數(shù)時(shí)保存在棧上;該塊對(duì)象的生命周期就是函數(shù)運(yùn)行期間。
- 3)在現(xiàn)實(shí)的實(shí)現(xiàn)中,當(dāng)函數(shù)內(nèi)的塊語(yǔ)法不包含自動(dòng)變量的時(shí)候,就沒必要進(jìn)行復(fù)制值,所以塊對(duì)象的內(nèi)存區(qū)域也會(huì)被保存在靜態(tài)數(shù)據(jù)區(qū)。
- 4)block代碼塊被保存在堆或者靜態(tài)區(qū)中,不會(huì)被保存在棧中,如下圖可以說明這一點(diǎn)。
示例
- (void)function {int i;int (^blocks[10])(); //定義一個(gè)塊對(duì)象類型的數(shù)組for (i = 0; i < 10; i++) { //for循環(huán)給數(shù)組賦值blocks[i] = ^{ return i; };}for (i = 0; i < 10; i++) { //打印數(shù)組中的內(nèi)容,就是每個(gè)數(shù)組存放的代碼塊的返回值NSLog(@"%d", blocks[i]());} } // 如上代碼,在非ARC環(huán)境下運(yùn)行結(jié)果是10個(gè)9,原因是雖然循環(huán)了十次,但是只有一個(gè)實(shí)體。 // 以上代碼在ARC環(huán)境下是正確的,后面做說明。3.塊對(duì)象的復(fù)制
- 函數(shù)內(nèi)的塊對(duì)象和局部變量的生命周期相同,都只是在函數(shù)的執(zhí)行期間。但是在函數(shù)的方法調(diào)用參數(shù)中直接代入塊對(duì)象也是塊對(duì)象的一種非常常見的用法,這時(shí)候使用與函數(shù)調(diào)用關(guān)系或棧狀態(tài)無關(guān)的塊對(duì)象是非常必要的。
- 有一個(gè)函數(shù)可以復(fù)制塊對(duì)象到新的堆內(nèi)存,通過使用該函數(shù),即使是在函數(shù)內(nèi)部定義的塊對(duì)象也能獨(dú)立于棧被持續(xù)的使用,此外還有一個(gè)函數(shù)可以釋放不需要的塊對(duì)象。
Block_copy( block )
- 1.參數(shù)為棧上的塊對(duì)象的時(shí)候,返回堆上的塊對(duì)象。參數(shù)為堆上的塊對(duì)象或者靜態(tài)區(qū)的塊對(duì)象,不進(jìn)行復(fù)制,直接返回原對(duì)象,但是會(huì)增加參數(shù)塊對(duì)象的引用計(jì)數(shù)。
Block_release( block )
- 2.減少參數(shù)塊對(duì)象的引用計(jì)數(shù)。當(dāng)引用計(jì)數(shù)減到0時(shí)候,塊對(duì)象被釋放。
- 3.在使用這些函數(shù)的時(shí)候,需要引入頭文件Block.h .堆上的塊對(duì)象使用引用計(jì)數(shù)的方式來管理。即使使用垃圾回收也必須成對(duì)出現(xiàn)。使用ARC時(shí)候可以不考慮這些,編譯器會(huì)自動(dòng)幫我們判斷什么時(shí)候釋放,什么時(shí)候保持。
4.指定特殊變量 __block
ARC下測(cè)試結(jié)果和總結(jié):
非ARC下測(cè)試結(jié)果和總結(jié):
使用block時(shí)候注意事項(xiàng):
使用注意事項(xiàng):
- 1)在塊內(nèi)改變外部變量的值時(shí)候,在外部變量前加__block,否則該值在block塊內(nèi)部是只讀的。
- 2)在引用某個(gè)實(shí)例變量或者所在控制器本身時(shí)候,在ARC下,要再前面加__weak如:__weak (typeof(self) weak self = self), 在mrc下用__block, 這樣做是為了避免內(nèi)存泄露和循環(huán)引用。
- 3)在使用block前需要對(duì)block指針做判空處理,如果是MRC的編譯環(huán)境下,要先release掉block對(duì)象。
- 4)在MRC的編譯環(huán)境下,block如果作為成員參數(shù)要copy一下將棧上的block拷貝到堆上(因?yàn)閎lock默認(rèn)是在棧上創(chuàng)建的,如果在定義block的作用于外部使用block那么需要使用copy將block放到堆上)//MRC下:_sucBlock = [callbackBlock copy]; 不copy block會(huì)在棧上被回收。
- 5)將block賦值為空,是解掉循環(huán)引用的重要方法。
- 6)還有一種改法,在block接口設(shè)計(jì)時(shí),將可能需要的變量作為形參傳到block中,從設(shè)計(jì)上解決循環(huán)引用的問題。
7)在多線程環(huán)境下(block中的weakSelf有可能被析構(gòu)的情況下),需要先將self轉(zhuǎn)為strong指針,避免在運(yùn)行到某個(gè)關(guān)鍵步驟時(shí)self對(duì)象被析構(gòu)。
第四、第五條合起來有個(gè)名詞叫weak–strong dance,來自于2011 WWDC Session #322 (Objective-C Advancements in Depth)以下代碼來自AFNetworking,堪稱使用weak–strong dance的經(jīng)典。
Review一下上面這段代碼,里面玄機(jī)不少。
- 第一行:__weak __typeof(self)weakSelf = self;
- 如之前第四條所說,為防止callback內(nèi)部對(duì)self強(qiáng)引用,weak一下。
- 其中用到了__typeof(self),這里涉及幾個(gè)知識(shí)點(diǎn):
- a. __typeof、typeof、typeof的區(qū)別
- 恩~~他們沒有區(qū)別,但是這牽扯一段往事,在早期C語(yǔ)言中沒有typeof這個(gè)關(guān)鍵字,__typeof、__typeof__是在C語(yǔ)言的擴(kuò)展關(guān)鍵字的時(shí)候出現(xiàn)的。
- typeof是現(xiàn)代GNU C++的關(guān)鍵字,從Objective-C的根源說,他其實(shí)來自于C語(yǔ)言,所以AFNetworking使用了繼承自C的關(guān)鍵字。
- b.對(duì)于老的LLVM編譯器上面這句話會(huì)編譯報(bào)錯(cuò),所以在很早的ARC使用者中流行__typeof(&*self)這種寫法,
原因如下大致說法是老LLVM編譯器會(huì)將__typeof轉(zhuǎn)義為 XXX類名 *const __strong的__strong和前面的__weak關(guān)鍵字對(duì)指針的修飾又沖突了,所以加上&*對(duì)指針的修飾。
第三行:__strong __typeof(weakSelf)strongSelf = weakSelf;
按照之前第五條的說法給轉(zhuǎn)回strong了,這里__typeof()里面寫的是weakSelf,里面寫self也沒有問題,因?yàn)閠ypeof是編譯時(shí)確定變量類型,所以這里寫self 不會(huì)被循環(huán)引用。第四、五、六行,如果不轉(zhuǎn)成strongSelf而使用weakSelf,后面幾句話中,有可能在第四句執(zhí)行之后self的對(duì)象可能被析構(gòu)掉,然后后面的StausBlock沒有執(zhí)行,導(dǎo)致邏輯錯(cuò)誤。
最后第五行,使用前對(duì)block判空。
轉(zhuǎn)載于:https://www.cnblogs.com/ShaoYinling/p/7821457.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的OC语言Block 续的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第三次个人作业
- 下一篇: 一:包装好和吹出去 二:三国心得