存放方式
局部block存放在栈区
block在执行copy操作后存放到堆区,像对象一样开始使用引用计数
全局block存放在全局区(代码段)
block与delegate的优劣比较
delegate 方式处理多回调会更方便一点
block方式业务代码更紧凑
block捕获变量
OC源码
- (void)initBlock {
__block OBJ *obj = [OBJ new];
NSString *bb = @"你好,bb!";
__block int cc = 33;
int dd = 55;
// __weak typeof(self) weakSelf = self;
//void(^temp)(NSString *bb) =
^(NSString *bbs) {
// bb = @"切,什么鬼";
NSLog(@"%@----> %@ dd=%d", bb, obj, dd);
cc = 55;
self.name = @"123";
};
//_block = temp;
}
__block修饰的局部变量会被包装成结构体
// __block int cc 被包装成下面的结构体
struct __Block_byref_cc_0 {
void *__isa;
__Block_byref_cc_0 *__forwarding;
int __flags;
int __size;
int cc;
};
// __block OBJ *obj被包装成下面的结构体
struct __Block_byref_obj_0 {
void *__isa;
__Block_byref_obj_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
OBJ *obj;
};
block对应的编译器生成的结构体
struct __TestBlock__initBlock_block_impl_0 {
struct __block_impl impl;
struct __TestBlock__initBlock_block_desc_0* Desc;
NSString *bb;
int dd;
TestBlock *self; // 捕获self
__Block_byref_obj_0 *obj; // by ref // 捕获 __block OBJ *obj
__Block_byref_cc_1 *cc; // by ref // 捕获 __block int cc
/// 构造函数
__TestBlock__initBlock_block_impl_0(void *fp, struct __TestBlock__initBlock_block_desc_0 *desc, NSString *_bb, int _dd, TestBlock *_self, __Block_byref_obj_0 *_obj, __Block_byref_cc_1 *_cc, int flags=0) : bb(_bb), dd(_dd), self(_self), obj(_obj->__forwarding), cc(_cc->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
block 编译后对应的c函数
/// block 对应的c函数
static void __TestBlock__initBlock_block_func_0(struct __TestBlock__initBlock_block_impl_0 *__cself, NSString *bbs) {
__Block_byref_obj_0 *obj = __cself->obj; // bound by ref
__Block_byref_cc_1 *cc = __cself->cc; // bound by ref
NSString *bb = __cself->bb; // bound by copy
int dd = __cself->dd; // bound by copy
TestBlock *self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_kb_hrh7kmq16p729gwbvk_9qfv80000gn_T_TestBlock_391643_mi_1, bb, (obj->__forwarding->obj), dd);
(cc->__forwarding->cc) = 55;
((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)self, sel_registerName("setName:"), (NSString *)&__NSConstantStringImpl__var_folders_kb_hrh7kmq16p729gwbvk_9qfv80000gn_T_TestBlock_391643_mi_2);
}
block中避免保留环
// 弱引用方式
__weak typeof(self) weakSelf = self
// 或者self对象作为block的参数
__forwarding 的作用
当block从栈拷贝到堆后,捕获对象变成两份,栈上一份,堆上一份。为了保证捕获对象的一致性,两处的__forwarding都指向堆上的捕获对象,而所有对捕获对象堆操作的操作都改成对__forwarding的操作。
网友评论