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