Block的那些事
Block 最大的便利就是簡化的回調過程,實現編程之美。?使用Block要謹記別造成對象互相引用導致對象無法被釋放。??
關于閉包:
http://baike.baidu.com/view/648413.htm
? ? ? ? ? 閉包是可以包含自由(未綁定到特定對象)變量的代碼塊;這些變量不是在這個代碼塊內或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義。“閉包” 一詞來源于以下兩者的結合:要執行的代碼塊(由于自由變量被包含在代碼塊中,這些自由變量以及它們引用的對象沒有被釋放)和為自由變量提供綁定的計算環境(作用域)。在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python,objective c 等語言中都能找到對閉包不同程度的支持。
objective c 中的的閉包,是通過block實現的。Apple在C,Objective-C和C++中擴充了Block這種文法的,并且在GCC4.2中進行了支持。你可以把它理解為函數指針,匿名函數,閉包,lambda表達式,這里暫且用塊對象來表述,因為它們之間還是有些許不同的。
如果以內聯方式使用塊對象,則無需聲明。塊對象聲明語法與函數指針聲明語法相似,但是塊對象應使用脫字符(^)而非星號指針 (*);
?
關于Block官方文檔:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html
Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed.
You can use blocks to compose function expressions that can be passed to API, optionally stored, and used by multiple threads. Blocks are particularly useful as a callback because the block carries both the code to be executed on callback and the data needed during that execution.
Block objects are a C-level syntactic and runtime feature that allow you to compose function expressions that can be passed as arguments, optionally stored, and used by multiple threads. The function expression can reference and can preserve access to local variables. In other languages and environments, a block object is sometimes also called a closure or a lambda. You use a block when you want to create units of work (that is, code segments) that can be passed around as though they are values. Blocks offer more flexible programming and more power. You might use them, for example, to write callbacks or to perform an operation on all the items in a collection.
?
關于Block的內部實現:
http://blog.csdn.net/jasonblog/article/details/8077340
或原文地址:http://coolshell.cn/articles/8309.html
使用Clang命令查看中間代碼:
clang src.m -rewrite-objc -o dis.cpp
下面Objective-C代碼中的3個block,
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #import <Foundation/Foundation.h> ? int(^maxBlk)(int,int) = ^(intm,intn){returnm > n ? m : n; }; ? intmain(intargc,constchar* argv[]) { ????^{printf("Hello, World!\n"); } (); ? ????inti = 1024; ????void(^blk)(void) = ^{printf("%d\n", i); }; ????blk(); ? ????return0; } |
會產生對應的3個函數:
| 1 2 3 | __maxBlk_block_func_0 __main_block_func_0 __main_block_func_1 |
可見函數的命名規則為:__{$Scope}_block_func_{$index}。其中{$Scope}為block所在函數,如果{$Scope}為全局就取block本身的名稱;{$index}表示該block在{$Scope}作用域內出現的順序(第幾個block)。
Block結構體的實現:
以下代碼為例:
BLOCK的實現
__main_block_func_0的結構:
?
__main_block_impl_0類似為self或this。結構為:
__main_block_desc_0結構為:(從實現可看出為__main_block_impl_0的大小)
?所以
結論:
聲明時,block本身,即__main_block_impl_0把數據保存在其結構體中,
執行時,調用block的對應函數,即FuncPtr,傳遞的參數是其自身__cself,即__main_block_impl_0
?
關于__block聲明的實現:
聲明__block對應會生成對應生成結構體:
?
則block塊聲明實現時,變為:
調用FuncPtr函數時,執行內容為:
__block的本質是:
使用__block類型指示符的本質就是引入了__Block_byref_{$var_name}_{$index}結構體,而被__block關鍵字修飾的變量就被放到這個結構體中。另外,block結構體通過引入__Block_byref_{$var_name}_{$index}指針類型的成員,得以間接訪問到外部變量。
(注:其實就是為了從值傳遞修改為引用,從而有了修改內容的能力)
?
關于block的copy。
When a block is copied, it creates strong references to object variables used within the block. If you use a block within the implementation of a method:
- If you access an instance variable by reference, a strong reference is made to?self;
- If you access an instance variable by value, a strong reference is made to the variable.
-
dispatch_async(queue,?^{?
//instanceVariable?is?used?by?reference,?self?is?retained?
doSomethingWithObject(instanceVariable);?
});
id?localVariable?=?instanceVariable;?
dispatch_async(queue,?^{?
//localVariable?is?used?by?value,?localVariable?is?retained?(not?self)
doSomethingWithObject(localVariable);?
});
總結:通過一系列demo測試驗證,Block塊的聲明,只是初始化其結構體,保留函數指針和block塊中變量,這個過程不會對block塊中變量進行strong references。當調用block時,通過結構體中的函數指針和保留的變量來實現方法調用。當block出了聲明區域時,系統會釋放結構體。當block需要delay執行時,如dispatch_async方法,需將block進行copy,這時會對block內變量進行strong references,且block結構體會copy到堆上。而實時調用block,如dispatch_sync方法或enumerateObjectsUsingBlock方法等方法,則直接調用保留的變量。當然,GCD方法在多線程上會數據線程安全做相應處理,但也不需要我們care。而類似NSArray的block相對很單純,使用時不需要過多考慮。
?
======================神奇的分隔線線======================
擇一的內容補充:http://www.cnblogs.com/biosli/archive/2013/05/29/iOS_Objective-C_Block.html#commentform
在經過copy之后,對象的類型從__NSStackBlock__變為了__NSMallocBlock__
在Objective-C的設計中,我沒見過copy一回把對象的類型也給變了的,再次說明了block是一種特殊的對象。
大家應該注意到__block標記的變量了吧,這個變量會隨著block對象上堆一塊上堆,這個部分上面的blogs和書中都有講解,我就不敘述了。
另外還有一種類型block的類型__NSGlobalBlock__,當block里面沒有局部變量的時候會block會變為這個類型,這個類型的retain/copy/release全都不會對對象有影響,可以當做靜態block理解。
__NSMallocBlock__對象再次copy,不會再產生新的對象而是對原有對象進行retain。
經過實驗幾個block類型的retain/copy/release的功能如下(非ARC環境):
?
說說ARC
上面的這些方法,說的都是非ARC編程的時候的注意事項,在ARC下很多規則都可以省略了。
因為在ARC下有個原則,只要block在strong指針底下過一道都會放到堆上。
看下面這個實驗:?
? ? {
? ? ? ? __blockint val = 10;
? ? ? ? __strong blk strongPointerBlock = ^{NSLog(@"val = %d", ++val);};
? ? ? ? NSLog(@"strongPointerBlock: %@", strongPointerBlock); //1 ? ? ? ?
? ? ? ? __weak blk weakPointerBlock = ^{NSLog(@"val = %d", ++val);};
? ? ? ? NSLog(@"weakPointerBlock: %@", weakPointerBlock); //2 ? ? ? ?
? ? ? ? NSLog(@"mallocBlock: %@", [weakPointerBlock copy]); //3 ? ? ? ?
? ? ? ? NSLog(@"test %@", ^{NSLog(@"val = %d", ++val);}); //4
? ? }
得到的日志:
2013-05-29 16:03:58.773 BlockTest[3482:c07] strongPointerBlock: <__NSMallocBlock__: 0x7625120>
2013-05-29 16:03:58.776 BlockTest[3482:c07] weakPointerBlock: <__NSStackBlock__: 0xbfffdb30>
2013-05-29 16:03:58.776 BlockTest[3482:c07] mallocBlock: <__NSMallocBlock__: 0x714ce60>
2013-05-29 16:03:58.777 BlockTest[3482:c07] test <__NSStackBlock__: 0xbfffdb18>
?
================ 華麗的分隔線?================
在垃圾回收機制里面,如果你同時使用__weak 和__block 來標識一個變量,那么該 block 將不會保證它是一直是有效的。
一個 block 的文本(通常是^{...})是一個代表 block 的本地棧數據結構地址。 因此該本地棧數據結構的作用范圍是封閉的復合狀態,所以你應該避免下面例子顯示的模式:?
void?dontDoThis()?{?void?(^blockArray[3])(void);?//?an?array?of?3?block?references
????for?(int?i?=?0;?i?<?3;?++i)?{?
????????blockArray[i]?=?^{?printf("hello,?%d\n",?i);?};?
????????//?WRONG:?The?block?literal?scope?is?the?"for"?loop?
????}
}
轉載于:https://www.cnblogs.com/simalone/archive/2012/03/12/2391369.html
總結
- 上一篇: 网站页首可关闭广告条
- 下一篇: HDU 3264 Open-air sh