iOS開發之block解析

2022-09-06 15:15:12 字數 4740 閱讀 1306

1. block的本質是乙個objective-c的物件。為什麼這麼說?

在objective-c中。runtime會在執行時依據物件的isa指標的指向,來度額定這個物件的型別。也能夠覺得乙個物件。它具有isa指標。就是乙個oc物件

2. 你怎麼知道block有isa指標呢。我們能夠通過clang命令將來看block的實現

//測試**

int main(int argc, const

char * ar**) ;

}return

0;}

轉化後:block語法被編譯器轉化成了以下的結構

struct

__main_block_impl_0

};

這個結構體由三部分組成impl的結構體(block 物件)+desc的結構體指標+建構函式,建構函式是用來對結構體做初始化的,剩下的那兩個結構體相應的實現例如以下

//impl的型別,block的相關實現資訊

struct __block_impl ;

//對於block的描寫敘述資訊

struct __main_block_desc_0 __main_block_desc_0_data = ;

block語法會被編譯器轉化為__main_block_impl_0的結構體。這個結構體由三部分組成:儲存block的相關實現資訊的_block_impl的結構體impl以及儲存block的描寫敘述資訊的__main_block_desc_0的結構體指標desc以及用來對block做初始化的構造方法。當中impl中的isa的成員說明了block是乙個oc物件。另乙個乙個函式指標指向了block的實現

3. block:事實上相當於c語言中的匿名函式。他能夠訪問外部變數或者物件

1.沒有函式名,最清純的block^;,最清純的函式最起碼要有個函式名

2. 帶有脫字元』^』

3.無論c語言還是oc函式都不支援函式巢狀。可是block實現了這個功能。它相當於乙個函式。可是他的視線卻是在另外乙個函式的內部。

#
自己主動變數:就是區域性變數。訪問區域性變數相當於函式呼叫時的值傳遞,不同意改動:當訪問了外部的變數,block 物件會把他訪問到的自己主動變數作為結構體成員加入到他的結構體當中,並且和原變數同名同值,不能改動的原因是,他們除了值一樣沒有聯絡,相當於值傳遞。上面說到,block相當於乙個函式,兩個函式裡面有同樣的的區域性變數。乙個變了並不會對另外乙個產生影響,所以編譯器乾脆就禁止了。實現例如以下

//block訪問外部自己主動變數

struct

__main_block_impl_0

};

#
2 . 靜態變數。在其作用範圍內僅僅有乙份記憶體,對其可讀可寫。相當於函式呼叫時的位址傳遞,block會將它訪問到的外部靜態變數的位址加入到自己的結構體成員中。有了位址,改值又有什麼不能夠呢,實現例如以下

//截獲靜態變數值

struct

__main_block_impl_0

};

#
3 . 全域性變數:在全域性能夠訪問到的。在全域性符號表中,與在block外訪問沒有差別,可讀可寫,無論怎樣都能夠訪問到

對於靜態、全域性變數的差別,能夠戳這裡我覺得能夠點

#
4 .物件。block能夠讀物件。

#
5 .物件的屬性:可讀可寫

#

6:對於成員變數

self 隱式迴圈引用:對於乙個或者多個成員變數,無論是否由 __block 修飾。block結構體會自己主動生成乙個成員 self。並且會引用成員變數所屬的物件例項,self 對於成員變數的改動都是通過物件 self 指標引用來實現的,block 內部對於成員變數的引用也是通過 block 結構體物件的成員 self 指標引用實現(可是會造成迴圈引用)。

4. 怎樣讓block能夠改動截獲的自己主動變數的值

4. 改動block所截獲的外部變數的值

上面說到:block不能夠改動自己主動變數或者物件的指向,這個時候,__block就像乙個救世主一樣出如今了我們面前,__block是怎樣實現改動自己主動變數值的,看一下他的實現

struct

__main_block_impl_0

};//被block修飾的自己主動變數被這種乙個結構體指標儲存了其位址

struct

__block_byref_a_0 ;

static void __main_block_func_0(struct

__main_block_impl_0 *__cself)

從上面能夠看出,當用__block修飾自己主動變數的時候,這個變數變成了乙個struct __block_byref_a_0的結構體例項,這個結構體有乙個指向自身的指標。forwarding,來保證這個變數無論在什麼位置都能被正確訪問到。(後面會詳解)

改動變數的過程:impl會依據自己儲存的指向struct __block_byref_a_0的結構體例項的指標,依據這個指標找到farwarding指標找到自己。在找到裡面儲存的自己主動變數,改動他的值。

5. block的儲存域

在前面,我們發現block本質是乙個物件。他有乙個isa指標,指向其所相應的類,那麼他所相應的類是什麼呢,這就牽扯到block的儲存域了

block的儲存於域有三種型別,當中isa指標指向這三種中的當中一種

1._nsconcretestackblock:儲存在棧上

2._nsconcreteglobalblock:儲存在資料區

3._nsconcretmallocblock:儲存在堆上

對於這三種型別的使用情況

_nsconcreteglobalblock:

1. 凡是全部的全域性block都儲存在資料區

2. 假設block中沒有截獲自己主動變數,block也在資料區

_nsconcretestackblock:

1. mrc:預設在棧區,block生命週期與其作用域相關

2.arc:大多數arc情況下的block是儲存在堆區的。僅僅有少部分在棧區。在棧區須要我們手動 copy 到堆區

_nsconcretmallocblock

mrc:通過copy的方法能夠將block從棧區拷貝到堆區

arc:大多數預設情況在堆區,有棧區的能夠通過copy/strong拷貝到堆區,僅僅要有乙個strong指向他,就會被拷貝到堆區

6. 通過copy將block從棧上拷貝到堆上

在棧上的變數的生命週期由編譯器來管理,與其作用域相關聯。出了作用域就會被釋放。可是堆上有程式猿自己管理或者arc管理,不會由於其出了作用域就被釋放

前面提到了乙個forwarding指標,用block修飾的自己主動變數會被儲存在乙個__block_byref_a_0的結構體指標中。這個指標中又有乙個指向自己的forwarding,那麼為什麼不直接找到其相應的值,而要通過這個指標呢,由於當block物件被從棧上賦值到堆上的時候。其內部用到的被block修飾的變數也會被賦值乙份放在堆上,然後讓棧上forwarding結構體指標指向堆上的結構體就能夠,這樣就能夠保證無論在棧上還是堆上。都能夠正確訪問到變數

arc 下須要不須要手動copy 的情況

當 block 被強引用時

系統的 api 中帶有 usingblock 時

block 作為函式返回值

那什麼時候須要我們手動 copy 呢?

當block 作為函式引數的時候,在 arc 下我們自己定義的 block 要寫上 copy。

關於copy的特點

假設原來在棧上,通過copy。被拷貝到堆上。

假設原來在全域性資料區,不會發生改變

假設在堆區:其引用計數加1

7. __block在arc和mrc下的差別

1、 用__block修飾,無論在mrc還是arc下,都能夠改動自己主動變數的值

2、在mrc下會避免迴圈引用,由於mrc下用__block修飾的變數不會被reatin,所以不會被 block 持有,所以能夠避免迴圈引用

3、 在arc下解決迴圈引用用的是weak:arc下的迴圈引用並非有__block引起的,是由於arc的特性。預設是強引用,所以為了解決迴圈引用,self一般用weak來修飾

8. 為什麼要用copy來修飾block

使用copy能夠將block從棧上轉移到堆上

mrc下,預設是棧上為了控制block生命週期,須要將其copy的堆上。不能夠用reatin取代。

arc下大多數情況預設是在堆上。可是由於一般遵循傳統,會寫上copy,可是能夠用strong來取代。

ios 全面解析block

block block變數格式 返回值型別 不可省略,最少void,沒有 變數名稱 引數 不可省略,至少 無引數無返回值 void noparamblock noparamblock void voidparamblock void void voidparamblock void blocknam...

ios 全面解析block

typedef int myblock void cfun void blockname1 myblock blockname2 void ocfun void blockname1 andotherblock myblock blockname2 在oc中呼叫cfun,直接cfun就可以了,但是o...

iOS開發 Block詳解

block是乙個非常有特色的語法,它可以把乙個 塊作為乙個變數來儲存,也可以通過函式傳遞變數,然後讓其他的物件來執行這一 塊。可以儲存傳遞並在其他地方執行的 塊,這是我對block的理解,也是我覺得block最吸引我的地方。直接定義 返回block指標 返回型別 可省略 引數型別 引數 沒有引數可省...