之前對block一知半解,知道用__block,__weak等去解決問題,卻沒有去深究過,這篇文章是對學習block的總結
要看block轉換為c++原始碼,用下面的方法轉換:
cd到.m所在資料夾, 輸入clang -rewrite-objc ***.m,就會在當前資料夾內自動生成對應的***.cpp檔案,雙擊開啟即可
看下oc轉換成c++的**
oc
typedef int(^block_t)(int);
- (void)testfunc ;
block(2);
}
c++
struct __block_impl ;
typedef int(*block_t)(int);
// @implementation testobj
**//block結構體**
struct __testobj__testfunc_block_impl_0
};**//block所呼叫的方法**
static int __testobj__testfunc_block_func_0(struct __testobj__testfunc_block_impl_0 *__cself, int count)
**//block附加資訊**
static struct __testobj__testfunc_block_desc_0 __testobj__testfunc_block_desc_0_data = ;
//**testfunc**
static void _i_testobj_testfunc(testobj * self, sel _cmd)
這麼一坨**,看起來就眼暈,多看幾遍就好了,最好是自己動手寫一下,然後轉換成c++,可以看出來block其實就是objective-c用來實現閉包的物件形式
1、全域性變數
2、全域性靜態變數
3、區域性靜態變數
4、區域性變數
oc
typedef int(^block_t)(int);
int global_val = 1;//全域性變數
static int static_global_val = 2;//全域性靜態變數
- (void)testfunc ;
block(2);
printf("---%d---%d---%d",global_val,static_global_val,static_val);
}
c++
struct __testobj__testfunc_block_impl_0
};static int __testobj__testfunc_block_func_0(struct __testobj__testfunc_block_impl_0 *__cself, int count)
可以看到全域性變數和全域性靜態變數,block內部沒有做操作;區域性靜態變數時,將指標傳遞到block的建構函式(// bound by copy注釋是編譯器自動新增的),區域性變數不可做賦值操作;注意:如果區域性變數是nsmutablearray 型別時,在block內部做addobject操作是允許的,但是不可為區域性變數重新賦值;
對於block,我們會遇到在外部修改區域性的值以後,再次呼叫block時,裡面的區域性變數的值仍然和之前是一樣的情況。。下面來看下如果只是呼叫區域性變數的話block的內部操作
oc
typedef int(^block_t)(int);
- (void)testfunc ;
block(2);
}
c++
struct __testobj__testfunc_block_impl_0
};static int __testobj__testfunc_block_func_0(struct __testobj__testfunc_block_impl_0 *__cself, int count)
可以看到,block中使用的區域性變數fmt,val被新增到了結構體中,沒有使用的則未新增。。函式體的**中,使用時取得是__cself中即結構體中的fmt和val,這兩個變數是值傳遞的,並沒有傳遞指標。。看來這就是外部變數的值改變時block內部值不變的原因了,也正是這個原因,block內部給外部的區域性變數賦值時會報錯。怎麼樣在block內部修改外部的值?怎麼讓區域性變數在block內外保持同步?就是__block
看下**
oc
- (void)testfunc ;
block();//20 20
a -= 20;
b += 30;
printf("%d, %d\n",a,b);//0 50
block(); //10 20
}
c++
struct __block_byref_a_0 ;
struct __testobj__testfunc_block_impl_0
};static void __testobj__testfunc_block_func_0(struct __testobj__testfunc_block_impl_0 *__cself)
static void __testobj__testfunc_block_copy_0(struct __testobj__testfunc_block_impl_0*dst, struct __testobj__testfunc_block_impl_0*src)
static void __testobj__testfunc_block_dispose_0(struct __testobj__testfunc_block_impl_0*src)
static struct __testobj__testfunc_block_desc_0 __testobj__testfunc_block_desc_0_data = ;
static void _i_testobj_testfunc(testobj * self, sel _cmd) ;
int b = 20;
block_t block = ((void (*)())&__testobj__testfunc_block_impl_0((void *)__testobj__testfunc_block_func_0, &__testobj__testfunc_block_desc_0_data, b, (__block_byref_a_0 *)&a, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->funcptr)((__block_impl *)block);
(a.__forwarding->a) -= 20;
b += 30;
printf("%d, %d\n",(a.__forwarding->a),b);
((void (*)(__block_impl *))((__block_impl *)block)->funcptr)((__block_impl *)block);
}
可以看到,被__block修飾後多了 __block_byref_a_0 這麼個結構體,在 __testobj__testfunc_block_impl_0 中 b 被表示為 int b,而加了__block的a則 表示為 __block_byref_a_0 *a; // by ref;下面就是
__block_byref_a_0
struct __block_byref_a_0 ;
在 _i_testobj_testfunc即testfun的方法中有a的宣告:attribute((blocks(byref))) __block_byref_a_0 a = ;
可以看到__forwarding是指向自身的,在__testobj__testfunc_block_impl_0中可以看到a(_a->__forwarding);即block的a是取的__forwarding;在block內和block外呼叫a的時候都用了a->__forwarding->a;這裡應該就是__block修飾符為什麼可以使block內部去修改block外部變數的關鍵
本文參考
ios底層原理總結 - 探尋block的本質
《objective-c-高階程式設計》乾貨三部曲(二):blocks篇
Block 學習筆記
一 什麼是block?a block is an anonymous inline collectionof code,and sometimes also called a closure 閉包是一種函式,它能夠讀取其它函式的內部變數。block 也相當於內聯函式,執行速度快,簡單方便 二 為什麼...
學習日記 block
block概念 1.內聯函式從源 層看,有函式的結構,而在編譯後,卻不具備函式的性質,編譯時,類似巨集替換,使用函式體替換呼叫處的函式名 2.block封裝了一段 可以在任何時候執行 3.block可以作為函式引數或者函式的返回值,而其本身又可以帶輸入引數或返回值 用途 在多執行緒 非同步任務 集合...
Objective C學習筆記 block
一 基本概念 1 block的作用 block封裝了一段 在任何時候都可以使用。block的標誌是 2 block的特點 block可以作為函式引數或者函式的返回值,而其本身又可以帶輸入引數或返回值,和函式很像。二 基本使用 1 定義block變數 1 無形參 無返回值 void myblock 定...