通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

block为什么能够捕获外界变量

block能够捕获外界变量的原因:在定义block的时候,外界变量被编译器转换成了结构体成员变量,并且在调用block的时候,这些变量的值会被拷贝到block的结构体实例中。这样一来,即使在block执行之后,这些变量的作用域已经结束,它们的值也能够保留下来,并且能够在block内部继续使用。

一、block能够捕获外界变量的原因

在定义Block的时候,外界变量被编译器转换成了结构体成员变量,并且在调用Block的时候,这些变量的值会被拷贝到Block的结构体实例中。这样一来,即使在Block执行之后,这些变量的作用域已经结束,它们的值也能够保留下来,并且能够在Block内部继续使用。这种特性就是Block所具有的闭包特性,也是它能够捕获外界变量的原因。

二、block是什么

block是一种封装了代码块的数据类型,可以在C、Objective-C和Swift中使用。它类似于函数或方法,但具有更灵活的特性,可以嵌套在其他代码块中使用,并且能够捕获外部变量。block可以作为参数传递给函数或方法,也可以作为返回值返回。在异步编程、多线程和事件处理等场景中,block被广泛应用。

block就是一个代码块, block是将函数及其执行上下文封装起来的对象,是一个匿名的函数对象, block也有isa。既然block内部封装了函数,那么它同样也有参数和返回值,本身也可以被作为参数在方法和函数间传递。

block标准语法:

return_type (^blockName)(var_type) = ^return_type (var_type varName) {
    // ...
};
blockName(var);

三、Block底层实现

block的底层实现是结构体,和类的底层实现类似,都有isa指针,可以把block当成是一个对象。下面通过创建一个控制台程序,来窥探block的底层实现。

block 的内存结构图:

Block_layout结构体成员含义如下:

  • isa: 指向所属类的指针,也就是block的类型
  • flags: 标志变量,在实现block的内部操作时会用到
  • Reserved: 保留变量
  • invoke: block执行时调用的函数指针,block内部的执行代码都在这个函数中
  • descriptor: block的详细描述,包含 copy/dispose 函数,处理block引用外部变量时使用
  • variables: block范围外的变量,如果block没有调用任何外部变量,该变量就不存在

Block_descriptor结构体成员含义如下:

  • reserved: 保留变量
  • size: block的内存大小
  • copy: 拷贝block中被 __block 修饰的外部变量
  • dispose: 和 copy 方法配置应用,用来释放资源

具体实现代码:

enum {
    BLOCK_REFCOUNT_MASK =     (0xffff),
    BLOCK_NEEDS_FREE =        (1 << 24),
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25),
    BLOCK_HAS_CTOR =          (1 << 26), /* Helpers have C++ code. */
    BLOCK_IS_GC =             (1 << 27),
    BLOCK_IS_GLOBAL =         (1 << 28),
    BLOCK_HAS_DESCRIPTOR =    (1 << 29)
};

/* Revised new layout. */
struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

struct Block_layout {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

延伸阅读1:block类型

  • NSGlobalBlock:没有访问auto变量
  • NSStackBlock:访问了auto变量
  • NSMallocBlock:调用了copy
相关文章