(知其因此然 主題1)OC中block的底層實現和具體運用

   這段時間一直忙着開發,很久沒來博客了,人氣稀少了很多,準備持續更新一個專題,主要談談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");}

編譯後:函數

struct __block_literal_1 {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(struct __block_literal_1 *);
    struct __block_descriptor_1 *descriptor;
};
 
void __block_invoke_1(struct __block_literal_1 *_block) {
    printf("OC is Good");
}
 
static struct __block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1;}

 咱們能夠觀察到:經過iSa指針,內容在編譯的時候就會被拷貝到block中,從而造成閉包.  先體會下底層實現,接下來將會重點介紹block在OC的中的常見應用場景,今天的知識點,一句話歸納:閉包就是可以讀取其它函數內部變量的函數.動畫

相關文章
相關標籤/搜索