美文网首页
iOS-block的本质

iOS-block的本质

作者: Arthur澪 | 来源:发表于2020-03-13 15:17 被阅读0次

block本质上也是一个OC对象,封装了函数调用以及函数调用环境,block内部也有个isa指针。

block的类型

既然block是OC对象,那它属于什么类型呢?

测试打印:一个block的类 及父类

void (^block)(void) =  ^{
      NSLog(@"123");
};

NSLog(@"block.class = %@",[block class]);
NSLog(@"block.class.superclass = %@",[[block class] superclass]);
NSLog(@"block.class.superclass.superclass = %@",[[[block class] superclass] superclass]);
NSLog(@"block.class.superclass.superclass.superclass = %@",[[[[block class] superclass] superclass] superclass]);


// ----- 打印的结果: 
// block.class = __NSGlobalBlock__
// block.class.superclass = __NSGlobalBlock
// block.class.superclass.superclass = NSBlock
// block.class.superclass.superclass.superclass = NSObject

上述例子中的 block的类型是__NSGlobalBlock(全局的)
继承关系为__NSGlobalBlock__ : __NSGlobalBlock : NSBlock : NSObject

而下面这个block的类型是__NSStackBlock__(栈空间的), 因为访问了auto变量。注意,这是MRC环境下看到的情况。

auto int a = 10;
void (^block)(void) =  ^{
      NSLog(@"a = %d",a);
};

而在ARC环境下,编译器会根据情况把block自动进行copy操作(将栈上的block复制到堆上),此时block的类型变成了__NSMallocBlock__ (堆空间的)

  • 结论:block共有3种类型(都继承自NSBlock
__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__  ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )
-
MRC下block属性的建议用copy修饰。
ARC下block属性可以用strong也行,因为会自动copy操作。

无论是MAC还是ARC:
当block为__NSStackBlock__类型时(在栈空间),无论对外面使用的是strong还是weak都不会对外面的对象进行强引用。

因为block如果在栈上,自己都随时可能消失,怎么能保住别人?

当block为__NSMallocBlock__类型时(在堆空间),block内部会根据strong或者weak对外界的对象进行强引用或弱引用。

block的底层结构

int age = 20;
void (^block)(void) =  ^{
     NSLog(@"age is %d",age);
 };
        
block();

将上面的代码转成C++代码:

int age = 20;
void (*block)(void) = &__main_block_impl_0(
                        __main_block_func_0, 
                        &__main_block_desc_0_DATA, 
                        age
                        );
// block的调用
block->FuncPtr(block);

看出,block的本质就是一个结构体对象__main_block_impl_0
结构体代码如下:

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int age;
    //构造函数(类似于OC中的init方法) _age是外面传入的
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    //isa指向_NSConcreteStackBlock 说明这个block就是_NSConcreteStackBlock类型的
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

结构体中第一个是struct __block_impl impl;如下:

struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
};

结构体中第二个是__main_block_desc_0;如下:

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size; // 结构体__main_block_impl_0 占用的内存大小
}

这里,如果block进行了copy操作(从栈空间变成堆空间)会增加copy和dispose。如下:

-
当block从堆中移除时,会调用block内部的dispose函数,在dispose内部释放捕获的变量。

结构体中第三个是age,也就是捕获的局部变量。

下面的函数,封装了block执行逻辑 :

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    int age = __cself->age;    // bound by copy
    
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_x4_920c4yq936b63mvtj4wmb32m0000gn_T_main_7f3f1b_mi_0,age);
}

相关文章

  • iOS-Block本质

    iOS-Block本质 参考篇:iOS-Block浅谈[https://www.jianshu.com/p/25a...

  • Objective-C的本质(6)——Block本质

    参考:iOS-Block本质iOS底层原理总结 - 探寻block的本质(一)iOS底层原理总结 - 探寻bloc...

  • iOS-Block本质

    参考篇:iOS-Block浅谈 前言:本文简述Block本质,如有错误请留言指正。 第一部分:Block本质 Q:...

  • iOS-Block本质

    Block本质上是一个OC对象,从底层结构就可以看的出来内部也有一个isa指针。Block封装了函数调用,以及函数...

  • iOS-block的本质

    block本质上也是一个OC对象,封装了函数调用以及函数调用环境,block内部也有个isa指针。 block的类...

  • iOS-block

    一. 查看block内部实现 1.编写block代码void (^DemoBlock)(int, int) = ^...

  • ios-Block

    概述: 能够截取自动变量的匿名函数 指向函数的指针 结构体 oc对象 使用: - 声明 - 定义(变量赋值) - ...

  • iOS-Block

    Block是一种匿名函数,也是一种Objective-C对象。 语法 返回值和参数列表都可以省略 声明 block...

  • iOS-block

    1.相关概念在这篇笔记开始之前,我们需要对以下概念有所了解。1.1 操作系统中的栈和堆注:这里所说的堆和栈与数据结...

  • iOS-Block

    block已经成为我在iOS编写中最为常用的回调方法 , 它简单便捷 , 取代了代理大部分的工作 , 今天整理一下...

网友评论

      本文标题:iOS-block的本质

      本文链接:https://www.haomeiwen.com/subject/cnafshtx.html