原文位址:點選打開連結
這段時間一直忙着開發,好久沒來部落格了,人氣稀少了不少,準備持續更新一個專題,主要談談OC底層的一些實作機制,并會對一些經典的面試題進行分析,感興趣的可以持續關注,第一講的主題是: BLock的實作和運用
我們一起來看看,經Clang編譯後的block結構如下:
1 struct Block_literal_1 {
2 void *isa;
3 int flags;
4 int reserved;
5 void (*invoke)(void *, ...);
6 struct Block_descriptor_1 {
7 unsigned long int reserved;
8 unsigned long int size;
9 // optional helper functions
10 void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
11 void (*dispose_helper)(void *src); // IFF (1<<25)
12 // required ABI.2014.5.25
13 const char *signature; // IFF (1<<30)
14 } *descriptor;
15 // imported variables
16 };
可以看到在Block結構體中含有isa指針,這就證明了Block其實就是對象,并具有一般對象的所有功能。這個isa指針被初始化為
_NSConcreteStackBlock
或者
_NSConcreteGlobalBlock
類的位址。在沒有開啟ARC的情況下,如果Block中包含有局部變量則isa被初始化為前者,否則就被初始化為後者。而當ARC開啟後,如果Block中包含有局部變量則isa被初始化為
_NSConcreteMallocBlock
,否則就被初始化為
_NSConcreteGlobalBlock
。invoke是一個函數指針,它指向的是Block被轉換成函數的位址。最後的imported variables部分是Block需要通路的外部的局部變量,他們在編譯就會被拷貝到Block中,這樣一來Block就是成為一個閉包了。
在iOS開發中我們在很多地方都能見到block的身影,如: (1)周遊數組或者字典 (2)視圖動畫 (3)排序 (4)通知 (5)錯誤處理 (6)多線程 (7)封裝變化點 ....... 是以,我們了解到Block是OC中的一種資料類型,在iOS開發中被廣泛使用,^是Block的特有标記,Block的實作代碼包含在{}之間.大多情況下,以内聯inline函數的方式被定義和使用,Block與C語言的函數指針有些相似,但使用起來更加靈活, 一個簡單的加法,使得block的定義一目了然:
1 int main(int argc, const char * argv[])
2 {
3
4 @autoreleasepool {
5 int (^sum)(int, int) = ^(int a, int b){
6 return a + b;
7 };
8 int add = sum(4, 5);
9 NSLog(@"%d", add);
10 }
11 return 0;
12 }
(一) Block可以使用在定義之前聲明的局部變量 (1)在定義Block時,會在Block中建立目前局部變量内容的副本(拷貝) (2)後續再對該變量的數值進行修改,不會影響Block中的數值 (3)如果需要在block中保持局部變量的數值變化,需要使用__block關鍵字 (4)使用__block關鍵字後,同樣可以在Block中修改該變量的數值
1 int main(int argc, const char * argv[])
2 {
3
4 @autoreleasepool {
5 int i = 0;
6 void (^myBlock)() = ^{
7 NSLog(@"%d",i);
8 };
9 i = 100;
10 myBlock();
11 }
12 return 0;
13 }
14
15 運作結果: i = 0
16
17 int main(int argc, const char * argv[])
18 {
19
20 @autoreleasepool {
21 __block int i = 0;
22 void (^myBlock)() = ^{
23 NSLog(@"%d",i);
24 };
25 i = 100;
26 myBlock();
27 }
28 return 0;
29 }
30
31
32 運作結果: i=100
(二) clang編譯block封裝的語句,一窺其廬山真面目
^{printf("OC is Good");}
編譯後:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
我們可以觀察到:通過iSa指針,内容在編譯的時候就會被拷貝到block中,進而形成閉包. 先體會下底層實作,接下來将會重點介紹block在OC的中的常見應用場景,今天的知識點,一句話概括:閉包就是能夠讀取其它函數内部變量的函數.