結(jié)構(gòu)
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
int f1 = 55;
int f2 = 55;
struct __Block_byref_a1_0 {
void *__isa;
__Block_byref_a1_0 *__forwarding;
int __flags;
int __size;
int a1;
};
struct __Animal__init_block_impl_0 {
struct __block_impl impl;
struct __Animal__init_block_desc_0* Desc;
int a2;
Animal *self;
int *c1;
int *c2;
__Block_byref_a1_0 *a1; // by ref
__Animal__init_block_impl_0(void *fp, struct __Animal__init_block_desc_0 *desc, int _a2, Animal *_self, int *_c1, int *_c2, __Block_byref_a1_0 *_a1, int flags=0) : a2(_a2), self(_self), c1(_c1), c2(_c2), a1(_a1->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static int __Animal__init_block_func_0(struct __Animal__init_block_impl_0 *__cself, int te1, int te2) {
__Block_byref_a1_0 *a1 = __cself->a1; // bound by ref
int a2 = __cself->a2; // bound by copy
Animal *self = __cself->self; // bound by copy
int *c1 = __cself->c1; // bound by copy
int *c2 = __cself->c2; // bound by copy
(a1->__forwarding->a1) = a2;
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)self, sel_registerName("setB1:"), ((int (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("b2")));
(*c1) = (*c2);
f1 = f2;
return te1 + te2;
}
static void __Animal__init_block_copy_0(struct __Animal__init_block_impl_0*dst, struct __Animal__init_block_impl_0*src) {_Block_object_assign((void*)&dst->a1, (void*)src->a1, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __Animal__init_block_dispose_0(struct __Animal__init_block_impl_0*src) {_Block_object_dispose((void*)src->a1, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __Animal__init_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __Animal__init_block_impl_0*, struct __Animal__init_block_impl_0*);
void (*dispose)(struct __Animal__init_block_impl_0*);
} __Animal__init_block_desc_0_DATA = { 0, sizeof(struct __Animal__init_block_impl_0), __Animal__init_block_copy_0, __Animal__init_block_dispose_0};
static instancetype _I_Animal_init(Animal * self, SEL _cmd) {
self = ((Animal *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Animal"))}, sel_registerName("init"));
if (self) {
__attribute__((__blocks__(byref))) __Block_byref_a1_0 a1 = {(void*)0,(__Block_byref_a1_0 *)&a1, 0, sizeof(__Block_byref_a1_0)};
;
int a2 = 0;
static int c1 = 0;
static int c2 = 0;
int e1 = 10;
int (*block)(int, int) = ((int (*)(int, int))&__Animal__init_block_impl_0((void *)__Animal__init_block_func_0, &__Animal__init_block_desc_0_DATA, a2, self, &c1, &c2, (__Block_byref_a1_0 *)&a1, 570425344));
int g = ((int (*)(__block_impl *, int, int))((__block_impl *)block)->FuncPtr)((__block_impl *)block, e1, 20);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4m_xm_v2tn54_z1csnt42kykgmm0000gn_T_Animal_0d46d1_mi_0, g);
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
__block int a1;
int a2 = 0;
static int c1 = 0;
static int c2 = 0;
int e1 = 10;
int (^block)(int, int) = ^(int te1, int te2){
a1 = a2;
self.b1 = self.b2;
c1 = c2;
f1 = f2;
return te1 + te2;
};
int g = block(e1, 20);
NSLog(@"%d", g);
}
return self;
}
結(jié)論:
- 局部變量 a1, a2, 因?yàn)?a1用__block修飾, 所以捕獲a1的地址, a2只是訪(fǎng)問(wèn)變量, 所以直接捕獲a2的值.
2.局部變量 self, 因?yàn)閎1和b2都是self的屬性, 所以直接捕獲了self.
- 靜態(tài)變量c1和c2是static修飾的, 捕獲了地址.
- 全局f1和f2, 沒(méi)有捕獲, 內(nèi)部直接訪(fǎng)問(wèn)的.
分類(lèi)
- _NSConcreteGlobalBlock :全局Block。
- 內(nèi)部沒(méi)有使用auto類(lèi)型變量的block, 就是NSGlobalBlock類(lèi)型
- copy后仍然是全局block;
-
NSGlobalBlock類(lèi)型的block, 不管怎樣類(lèi)型都不會(huì)改變, 依然在數(shù)據(jù)區(qū)
- _NSConcreteMallocBlock:堆Block。
- 堆block會(huì)捕獲外部變量,存儲(chǔ)于內(nèi)存的堆區(qū)。
- copy后引用計(jì)數(shù) +1
- _NSConcreteStackBlock:棧Block
在ARC下, 一個(gè)NSStackBlock類(lèi)型的block被一個(gè)__strong類(lèi)型的指針引用時(shí), 系統(tǒng)會(huì)將block自動(dòng)復(fù)制到堆區(qū), 變成堆block, 此時(shí)如果block內(nèi)部訪(fǎng)問(wèn)的不是被__weak修飾的變量, 會(huì)引用計(jì)數(shù) + 1, 需要等到block超出作用域, 才會(huì)引用數(shù) - 1
- 內(nèi)部使用了auto類(lèi)型變量的block, 就是NSStackBlock類(lèi)型
- copy后生成堆block
-
NSStackBlock類(lèi)型的block做為函數(shù)返回值時(shí), 會(huì)將返回的block復(fù)制到堆區(qū)
- 將NSStackBlock類(lèi)型的block賦值給__strong指針時(shí), 會(huì)將block復(fù)制到堆區(qū)
- block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí), block在堆區(qū)
- block作為GCD API的方法參數(shù)時(shí), block在堆區(qū)
調(diào)用 _Block_copy將 block 拷貝到堆上.
- _Block_copy時(shí)候, 如果block需要釋放,則直接釋放
- 如果block是globalBlock不需要copy, 直接返回.
- 通過(guò)malloc申請(qǐng)內(nèi)存空間用于接收block, 通過(guò) memmove 將block拷貝至新申請(qǐng)的內(nèi)存中.
通過(guò)_Block_object_assign將Block 捕獲的外界變量拷貝到堆中.
- 如果是普通對(duì)象,交給系統(tǒng)arc處理,拷貝對(duì)象指針,引用技術(shù)+1,外界變量不能釋放。
- 如果是block類(lèi)型的變量,通過(guò)_Block_copy操作,將block從棧區(qū)拷貝到堆區(qū)
- 如果是__block修飾的變量,調(diào)用_Block_byref_copy函數(shù),進(jìn)行內(nèi)存拷貝以及常規(guī)處理。
通過(guò) _Block_byref_copy 將 __block 修飾的變量拷貝到堆中
- 將傳入的對(duì)象,強(qiáng)轉(zhuǎn)為Block_byref結(jié)構(gòu)體類(lèi)型對(duì)象。保存
- 如果沒(méi)有將變量拷貝到堆上,就申請(qǐng)內(nèi)存進(jìn)行拷貝
- 如果已經(jīng)拷貝,則進(jìn)行處理并返回