oc block

存放方式

局部block存放在栈区
block在执行copy操作后存放到堆区,像对象一样开始使用引用计数
全局block存放在全局区(代码段)

block与delegate的优劣比较

block方式业务代码更紧凑,可读性更好,但是运行效率相对较低。
delegate可以包装多个方法

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的操作。

你可能感兴趣的:(oc block)