- block 调用 局部变量 NSObject 时
// source code
#import <Foundation/NSObject.h>
@interface Person: NSObject
@property (assign, nonatomic) int age;
@end
@implementation Person
@end
int main(int argc, char * argv[]) {
Person *person = [Person new];
void (^myHello)(int) = ^(int x){
person.age = x;
};
myHello(8);
}
// block impl
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr; // (void (*)(__block_impl *, int)
};
// FuncPtr
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
Person *person = __cself->person; // bound by copy
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
}
// block desc
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
// desc copy
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}
// desc dispose
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);}
// 自定义 block 声明
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *person;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
// person new
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
// myHello 的初始化以及赋值操作
void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, 570425344));
// 调用 FuncPtr
((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
总结:
block 持有局部变量时,自定义block 内部有一个Person field,此时的 person 会进行 引用计数操作,我们继续往下来看
_Block_object_assign 生效时机 捕获Person 对象 BLOCK_FIELD_IS_OBJECT 标志生效
接下来,我们看源代码
// 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 *destArg, const void *object, const int flags) {
const void **dest = (const void **)destArg;
switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
case BLOCK_FIELD_IS_OBJECT:
/*******
id object = ...;
[^{ object; } copy];
********/
_Block_retain_object(object); // +1
*dest = object;
break;
case BLOCK_FIELD_IS_BLOCK:
/*******
void (^object)(void) = ...;
[^{ object; } copy];
********/
*dest = _Block_copy(object); // block copy
break;
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
case BLOCK_FIELD_IS_BYREF:
/*******
// copy the onstack __block container to the heap
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__block ... x;
__weak __block ... x;
[^{ x; } copy];
********/
// 改造后的 _Block_byref 的copy
*dest = _Block_byref_copy(object);
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
/*******
// copy the actual field held in the __block container
// Note this is MRC unretained __block only.
// ARC retained __block is handled by the copy helper directly.
__block id object;
__block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
/*******
// copy the actual field held in the __block container
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__weak __block id object;
__weak __block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
default:
break;
}
}
在来看 dispose, __block 修饰的对象,会进行 byref_release, block 会释放, 捕获的 object 引用计数-1
// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
// to help dispose of the contents
void _Block_object_dispose(const void *object, const int flags) {
switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
case BLOCK_FIELD_IS_BYREF:
// get rid of the __block data structure held in a Block
_Block_byref_release(object);
break;
case BLOCK_FIELD_IS_BLOCK:
_Block_release(object);
break;
case BLOCK_FIELD_IS_OBJECT:
_Block_release_object(object);
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
break;
default:
break;
}
}
场景2,当有多个 对象捕获时,会发生什么?
#import <Foundation/NSObject.h>
@interface Person: NSObject
@property (assign, nonatomic) int age;
@end
@implementation Person
@end
@interface City: NSObject
@property (assign, nonatomic) int code;
@end
@implementation City
@end
int main(int argc, char * argv[]) {
Person *person = [Person new];
City *city = [City new];
void (^myHello)(int) = ^(int x){
person.age = x;
city.code = 2020;
};
myHello(8);
}
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
Person *person = __cself->person; // bound by copy
City *city = __cself->city; // bound by copy
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)city, sel_registerName("setCode:"), 2020);
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *person;
City *city;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, City *_city, int flags=0) : person(_person), city(_city) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
int main(int argc, char * argv[]) {
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
City *city = ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"));
void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, city, 570425344));
((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
}
总结:
可以看出,如果有多个捕获的对象时,在自定义的声明里,会明确出来,当生成代码时,保证其扩展行,真的不同的类型,都有单独的处理。
- 当对象被block 修饰时,会发生什么?
#import <Foundation/NSObject.h>
@interface Person: NSObject
@property (assign, nonatomic) int age;
@end
@implementation Person
@end
@interface City: NSObject
@property (assign, nonatomic) int code;
@end
@implementation City
@end
int main(int argc, char * argv[]) {
Person *person = [Person new];
__block City *city = [City new];
void (^myHello)(int) = ^(int x){
person.age = x;
city.code = 2020;
};
myHello(8);
}
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_func_0(struct __main_block_impl_0 *__cself, int x) {
__Block_byref_city_0 *city = __cself->city; // bound by ref
Person *person = __cself->person; // bound by copy
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)person, sel_registerName("setAge:"), (int)x);
((void (*)(id, SEL, int))(void *)objc_msgSend)((id)(city->__forwarding->city), sel_registerName("setCode:"), 2020);
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *person;
__Block_byref_city_0 *city; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, __Block_byref_city_0 *_city, int flags=0) : person(_person), city(_city->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_city_0 {
void *__isa;
__Block_byref_city_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
City *city;
};
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 __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
int main(int argc, char * argv[]) {
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
__attribute__((__blocks__(byref))) __Block_byref_city_0 city = {(void*)0,(__Block_byref_city_0 *)&city, 33554432, sizeof(__Block_byref_city_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"))};
void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, (__Block_byref_city_0 *)&city, 570425344));
((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
}
总结:针对__block 修饰的,会构造一个 byref ,持有被修饰的对象
在进行,copy,dispose ,有对应的函数
int main(int argc, char * argv[]) {
Person *person = [Person new];
__block City *city = [City new];
__block int y = 0;
void (^myHello)(int) = ^(int x){
person.age = x;
city.code = 2020;
y = 10;
};
myHello(8);
}
struct __Block_byref_city_0 {
void *__isa;
__Block_byref_city_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
City *city;
};
struct __Block_byref_y_1 {
void *__isa;
__Block_byref_y_1 *__forwarding;
int __flags;
int __size;
int y;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *person;
__Block_byref_city_0 *city; // by ref
__Block_byref_y_1 *y; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, __Block_byref_city_0 *_city, __Block_byref_y_1 *_y, int flags=0) : person(_person), city(_city->__forwarding), y(_y->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->city, (void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->y, (void*)src->y, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->city, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->y, 8/*BLOCK_FIELD_IS_BYREF*/);}
int main(int argc, char * argv[]) {
Person *person = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("new"));
__attribute__((__blocks__(byref))) __Block_byref_city_0 city = {(void*)0,(__Block_byref_city_0 *)&city, 33554432, sizeof(__Block_byref_city_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((City *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("City"), sel_registerName("new"))};
__attribute__((__blocks__(byref))) __Block_byref_y_1 y = {(void*)0,(__Block_byref_y_1 *)&y, 0, sizeof(__Block_byref_y_1), 0};
void (*myHello)(int) = ((void (*)(int))&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, person, (__Block_byref_city_0 *)&city, (__Block_byref_y_1 *)&y, 570425344));
((void (*)(__block_impl *, int))((__block_impl *)myHello)->FuncPtr)((__block_impl *)myHello, 8);
}
总结:可以看出 __block 修饰的基本数据类型,是没有copy,dispose操作的
网友评论