在使用 block 的時候想修改外部的值,一般都是需要時用 __block 修飾才能修改,但是有乙個些「可變集合類」屬於例外和一些例外情況。
第一種情況 __block修飾非集合類
__block nsinteger number = 1;
block block = ^(nsinteger a) ;
nsinteger b = block(5);
nslog(@"b=%ld", b);
複製**
輸出的結果是
2017-04-20 09:33:24.709179+0800 block[24319:2750379] b=6
複製**
第二種情況 沒有__block修飾的可變集合類nsmutablearray *array1 = [nsmutablearray new];
[array1 addobject:@0];
block block = ^(nsinteger a) ;
nsinteger b = block(5);
nslog(@"b=%ld", b);
nslog(@"array=%@", array1);
複製**
輸出的結果是
2017-04-20 09:33:24.709179+0800 block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 block[24319:2750379] array=(0,1
)複製**
第三種情況 __block修飾的可變集合類__block nsmutablearray *array1 = [nsmutablearray new];
[array1 addobject:@0];
block block = ^(nsinteger a) ;
nsinteger b = block(5);
nslog(@"b=%ld", b);
nslog(@"array=%@", array1);
複製**
輸出的結果是
2017-04-20 09:33:24.709179+0800 block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 block[24319:2750379] array=(2)
複製**
第四種情況 沒有__block修飾屬於當前物件屬性的可變集合類self.array1 = [nsmutablearray new];
[self.array1 addobject:@0];
block block = ^(nsinteger a) ;
nsinteger b = block(5);
nslog(@"b=%ld", b);
nslog(@"array=%@", array1);
複製**
輸出的結果是
2017-04-20 09:33:24.709179+0800 block[24319:2750379] b=5
2017-04-20 09:33:24.709399+0800 block[24319:2750379] array=(2)
複製**
總結
我們從上面的例子可以總結出來以下結果
如果沒有使用__block
修飾會發生什麼呢?
如圖,系統會直接提示錯誤。 分析
知道結果之後,我們分析一下原因
1、為什麼__block
修飾之後我們可以賦值呢?
使用clang -rewrite-objc main.m
編譯一下得到以下結果
對比之後我們可以發現(系統也給了注釋)有沒有__block
的區別就是
nsmutablearray *array = __cself->array1; // bound by copy
__block_byref_array1_1 *array1 = __cself->array1; // bound by ref
複製**
只有拷貝指標的才能執行賦值。
2、為什麼當前類屬性我們可以賦值呢?
同樣編譯一下可得
因為self.
呼叫了屬性的set方法,使用runtime實現訊息傳送,不過可能會存在記憶體洩露。
不用self.
也可以實現賦值,
_array1 = array2;
複製**
編譯後是
(*(nsmutablearray **)((char *)self + objc_ivar_$_test
$_array1)) = array2;
複製**
3、為什麼沒有__block
的可變集合類我們可以修改其中的物件呢?
從 1 的第一張圖我們可以看到[array1 addobject:@1];
編譯之後的是
((void (*)(id, sel, objecttype))(void *)objc_msgsend)((id)array1, sel_registername("addobject:"), (id)((nsnumber *(*)(class, sel, int))(void *)objc_msgsend)(objc_getclass("nsnumber"), sel_registername("numberwithint:"), 1));
複製**
同 2 呼叫的set方法,此處也是訊息傳送。
水平有限,如有錯誤還請指出~
block 塊的內部結構
每個oc物件都佔據著某個記憶體區域,因為例項變數的個數及物件所包含的關聯資料互不相同,所以每個物件所佔的記憶體區域大小也是有大有小,塊本身也是物件,在存放塊物件的記憶體區域中,首個變數是指向class物件的指標,該指標叫做isa。其餘記憶體裡含有塊丟向正常運轉所需的各種資訊。如下 塊 void is...
關於block介面傳值
不知道大家 對block的介面傳值了解的如何,我簡單的介紹一下吧。用block可以定義任意的 片段,可以將其像物件一樣傳入另乙個方法,是c級別的語法,和c中的函式指標很類似。進入正題吧,比如我們從第乙個viewcontroller push到第二個viewcontroller 第乙個viewcont...
iOS 揭露Block的內部實現原理
想必大家對block都很熟悉了,雖然都會用,但是你真的知道它的原理嗎?比如為什麼要加上 block,這個修飾符到底有什麼用?不加會有什麼後果?block又是如何實現的等等。該篇文章就為大家揭曉關於block的實現原理 先給出問題,大家思考下結果吧,如果分別呼叫以下兩個方法,結果如何?void blo...