Block捕获变量:
-
局部变量:基本数据类型:捕获值;对象型:捕获值和所有权修饰符
-
静态局部变量:捕获地址
-
全局变量:不捕获
-
静态全局变量:不捕获
捕获局部变量:非对象、对象、__block
(非对象)、__block
(对象)。
捕获非对象:
void blockStudy()
{
dispatch_block_t myBlock;
{
int a = 0;
myBlock = ^() {
if (a > 0) {
}
};
}
}
// ==>
void blockStudy()
{
dispatch_block_t myBlock;
{
int a = 0;
myBlock = ((void (*)())&__blockStudy_block_impl_0((void *)__blockStudy_block_func_0, &__blockStudy_block_desc_0_DATA, a));
}
}
struct __blockStudy_block_impl_0 {
struct __block_impl impl;
struct __blockStudy_block_desc_0* Desc;
int a;
__blockStudy_block_impl_0(void *fp, struct __blockStudy_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __blockStudy_block_desc_0 {
size_t reserved;
size_t Block_size;
} __blockStudy_block_desc_0_DATA = { 0, sizeof(struct __blockStudy_block_impl_0)};
捕获对象:
void blockStudy()
{
dispatch_block_t myBlock;
{
MyObject *myObject = [MyObject new];
myBlock = ^() {
myObject = [MyObject new];
};
}
}
// ==>
void blockStudy()
{
dispatch_block_t myBlock;
{
MyObject *myObject = ((MyObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MyObject"), sel_registerName("new"));
myBlock = ((void (*)())&__blockStudy_block_impl_0((void *)__blockStudy_block_func_0, &__blockStudy_block_desc_0_DATA, myObject, 570425344));
}
}
struct __blockStudy_block_impl_0 {
struct __block_impl impl;
struct __blockStudy_block_desc_0* Desc;
MyObject *__strong myObject;
__blockStudy_block_impl_0(void *fp, struct __blockStudy_block_desc_0 *desc, MyObject *__strong _myObject, int flags=0) : myObject(_myObject) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __blockStudy_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __blockStudy_block_impl_0*, struct __blockStudy_block_impl_0*);
void (*dispose)(struct __blockStudy_block_impl_0*);
} __blockStudy_block_desc_0_DATA = { 0, sizeof(struct __blockStudy_block_impl_0), __blockStudy_block_copy_0, __blockStudy_block_dispose_0};
static void __blockStudy_block_copy_0(struct __blockStudy_block_impl_0*dst, struct __blockStudy_block_impl_0*src) {_Block_object_assign((void*)&dst->myObject, (void*)src->myObject, 3/*BLOCK_FIELD_IS_OBJECT*/);}
可以发现__blockStudy_block_desc_0
相比捕获非对象的多了两个函数指针:copy
、dispose
。当block被拷贝到堆上面时copy函数会执行,调用_Block_object_assign
拷贝捕获的对象的地址并增加该对象的引用计数。
捕获__block(非对象)
void blockStudy()
{
dispatch_block_t myBlock;
{
__block int myInt = 0;
myBlock = ^() {
myInt = 1;
};
}
}
// ==>
void blockStudy()
{
dispatch_block_t myBlock;
{
__attribute__((__blocks__(byref))) __Block_byref_myInt_0 myInt = {(void*)0,(__Block_byref_myInt_0 *)&myInt, 0, sizeof(__Block_byref_myInt_0), 0};
myBlock = ((void (*)())&__blockStudy_block_impl_0((void *)__blockStudy_block_func_0, &__blockStudy_block_desc_0_DATA, (__Block_byref_myInt_0 *)&myInt, 570425344));
}
}
struct __Block_byref_myInt_0 {
void *__isa;
__Block_byref_myInt_0 *__forwarding;
int __flags;
int __size;
int myInt;
};
struct __blockStudy_block_impl_0 {
struct __block_impl impl;
struct __blockStudy_block_desc_0* Desc;
__Block_byref_myInt_0 *myInt; // by ref
__blockStudy_block_impl_0(void *fp, struct __blockStudy_block_desc_0 *desc, __Block_byref_myInt_0 *_myInt, int flags=0) : myInt(_myInt->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __blockStudy_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __blockStudy_block_impl_0*, struct __blockStudy_block_impl_0*);
void (*dispose)(struct __blockStudy_block_impl_0*);
} __blockStudy_block_desc_0_DATA = { 0, sizeof(struct __blockStudy_block_impl_0), __blockStudy_block_copy_0, __blockStudy_block_dispose_0};
static void __blockStudy_block_copy_0(struct __blockStudy_block_impl_0*dst, struct __blockStudy_block_impl_0*src) {_Block_object_assign((void*)&dst->myInt, (void*)src->myInt, 8/*BLOCK_FIELD_IS_BYREF*/);}
这里和捕获对象自由变量的block相比同样也有copy函数指针,不过在调用_Block_object_assign
传的第三个参数不一样。
捕获__block(对象)
void blockStudy()
{
dispatch_block_t myBlock;
{
__block MyObject *myObject = [MyObject new];
myBlock = ^() {
myObject = [MyObject new];
};
}
}
// ==>
void blockStudy()
{
dispatch_block_t myBlock;
{
__attribute__((__blocks__(byref))) __Block_byref_myObject_0 myObject = {(void*)0,(__Block_byref_myObject_0 *)&myObject, 33554432, sizeof(__Block_byref_myObject_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((MyObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("MyObject"), sel_registerName("new"))};
myBlock = ((void (*)())&__blockStudy_block_impl_0((void *)__blockStudy_block_func_0, &__blockStudy_block_desc_0_DATA, (__Block_byref_myObject_0 *)&myObject, 570425344));
}
}
struct __Block_byref_myObject_0 {
void *__isa;
__Block_byref_myObject_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
MyObject *__strong myObject;
};
struct __blockStudy_block_impl_0 {
struct __block_impl impl;
struct __blockStudy_block_desc_0* Desc;
__Block_byref_myObject_0 *myObject; // by ref
__blockStudy_block_impl_0(void *fp, struct __blockStudy_block_desc_0 *desc, __Block_byref_myObject_0 *_myObject, int flags=0) : myObject(_myObject->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __blockStudy_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __blockStudy_block_impl_0*, struct __blockStudy_block_impl_0*);
void (*dispose)(struct __blockStudy_block_impl_0*);
} __blockStudy_block_desc_0_DATA = { 0, sizeof(struct __blockStudy_block_impl_0), __blockStudy_block_copy_0, __blockStudy_block_dispose_0};
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __blockStudy_block_copy_0(struct __blockStudy_block_impl_0*dst, struct __blockStudy_block_impl_0*src) {_Block_object_assign((void*)&dst->myObject, (void*)src->myObject, 8/*BLOCK_FIELD_IS_BYREF*/);}
这里的block同样有copy函数指针,但是__block变量
的结构体__Block_byref_myObject_0
也多了两个函数指针:__Block_byref_id_object_copy
和__Block_byref_id_object_dispose
。当block被拷贝到堆上面时,__block变量
的结构体__Block_byref_myObject_0
也会被拷贝到堆上面,这时__Block_byref_id_object_copy
就会被调用。
_Block_object_assign
看看_Block_object_assign
的源码:
/*
* When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
* to do the assignment.
*/
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
//printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
_Block_assign_weak(object, destAddr);
}
else {
// do *not* retain or *copy* __block variables whatever they are
_Block_assign((void *)object, destAddr);
}
}
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
// copying a __block reference from the stack Block to the heap
// flags will indicate if it holds a __weak reference and needs a special isa
_Block_byref_assign_copy(destAddr, object, flags);
}
// (this test must be before next one)
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
// copying a Block declared variable from the stack Block to the heap
_Block_assign(_Block_copy_internal(object, flags), destAddr);
}
// (this test must be after previous one)
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
//printf("retaining object at %p\n", object);
_Block_retain_object(object);
//printf("done retaining object at %p\n", object);
_Block_assign((void *)object, destAddr);
}
}
如果block捕获了对象自由变量,在拷贝的时候_Block_object_assign
传入的是BLOCK_FIELD_IS_OBJECT
,这时候会强引用这个对象,再拷贝地址。
如果block捕获了__block变量
,不管是非对象还是对象,在拷贝时_Block_object_assign
传入的是BLOCK_FIELD_IS_BYREF
,这时拷贝的是__block变量
,把__block变量
从栈拷贝到堆。
__block变量
的拷贝同样调用_Block_object_assign
,这时第三个参数为BLOCK_BYREF_CALLER|BLOCK_FIELD_IS_OBJECT
。
block对对象的持有是在_Block_object_assign
执行时完成的。
block会强引用__block结构体
,而__block结构体
强引用对象自由变量。
__weak修饰符
void blockStudy()
{
dispatch_block_t myBlock;
{
NSObject *myObject = [NSObject new];
__weak NSObject *weakMyObjetc = myObject;
myBlock = ^() {
NSLog(@"%@", weakMyObjetc);
};
}
}
// ==>
void blockStudy()
{
dispatch_block_t myBlock;
{
NSObject *myObject = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new"));
__attribute__((objc_ownership(weak))) NSObject *weakMyObjetc = myObject;
myBlock = ((void (*)())&__blockStudy_block_impl_0((void *)__blockStudy_block_func_0, &__blockStudy_block_desc_0_DATA, weakMyObjetc, 570425344));
}
}
struct __blockStudy_block_impl_0 {
struct __block_impl impl;
struct __blockStudy_block_desc_0* Desc;
NSObject *__weak weakMyObjetc;
__blockStudy_block_impl_0(void *fp, struct __blockStudy_block_desc_0 *desc, NSObject *__weak _weakMyObjetc, int flags=0) : weakMyObjetc(_weakMyObjetc) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __blockStudy_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __blockStudy_block_impl_0*, struct __blockStudy_block_impl_0*);
void (*dispose)(struct __blockStudy_block_impl_0*);
} __blockStudy_block_desc_0_DATA = { 0, sizeof(struct __blockStudy_block_impl_0), __blockStudy_block_copy_0, __blockStudy_block_dispose_0};
static void __blockStudy_block_copy_0(struct __blockStudy_block_impl_0*dst, struct __blockStudy_block_impl_0*src) {_Block_object_assign((void*)&dst->weakMyObjetc, (void*)src->weakMyObjetc, 3/*BLOCK_FIELD_IS_OBJECT*/);}
block捕获变量时把所有权修饰符也捕获了:NSObject *__weak weakMyObjetc
,可是拷贝的时候_Block_object_assign
传入的同样是3/*BLOCK_FIELD_IS_OBJECT*/
,并没有区分?进一步查看_Block_object_assign
的汇编代码:
___copy_helper_block_: ## @__copy_helper_block_
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp6:
.cfi_def_cfa_offset 16
Ltmp7:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp8:
.cfi_def_cfa_register %rbp
subq $48, %rsp
movq %rdi, -8(%rbp)
movq %rsi, -16(%rbp)
movq -16(%rbp), %rsi
movq %rsi, %rdi
movq -8(%rbp), %rax
movq %rax, %rcx
addq $40, %rdi
movq %rcx, %rdx
addq $40, %rdx
movq %rdi, -24(%rbp) ## 8-byte Spill
movq %rdx, %rdi
movq -24(%rbp), %rdx ## 8-byte Reload
movq %rsi, -32(%rbp) ## 8-byte Spill
movq %rdx, %rsi
movq %rcx, -40(%rbp) ## 8-byte Spill
movq %rax, -48(%rbp) ## 8-byte Spill
callq _objc_copyWeak
movq -40(%rbp), %rax ## 8-byte Reload
addq $32, %rax
movq -32(%rbp), %rcx ## 8-byte Reload
movq 32(%rcx), %rdx
movq -48(%rbp), %rsi ## 8-byte Reload
movq $0, 32(%rsi)
movq %rax, %rdi
movq %rdx, %rsi
callq _objc_storeStrong
addq $48, %rsp
popq %rbp
retq
.cfi_endproc
.align 4, 0x90
可以看到它调用了两个方法,分别是_objc_copyWeak
和_objc_storeStrong
,从这里可以看出weak和strong的确是使用了不用的方法对待的。
网友评论