block 內部修改值

2021-09-24 06:41:41 字數 2941 閱讀 6526

在使用 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...