当前位置: 首页 > news >正文

iOS——Block签名

首先来看block结构体对象Block_layout(等同于clang编译出来的__Block_byref_a_0

#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {uintptr_t reserved;uintptr_t size;
};#define BLOCK_DESCRIPTOR_2 1
struct Block_descriptor_2 {// requires BLOCK_HAS_COPY_DISPOSEBlockCopyFunction copy;BlockDisposeFunction dispose;
};#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {// requires BLOCK_HAS_SIGNATUREconst char *signature;const char *layout;     // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};struct Block_layout {void *isa;volatile int32_t flags; // contains ref countint32_t reserved;BlockInvokeFunction invoke;struct Block_descriptor_1 *descriptor; //// imported variables
};

其中Block_layout是基础的block结构空间,而部分block则拥有Block_descriptor_2Block_descriptor_3结构,其中的flags标识记录了一些信息

  • 第1位:释放标记,一般常用BLOCK_NEEDS_FREE做位与操作,一同传入flags,告知该block可释放
  • 第16位:存储引用计数的值,是一个可选参数
  • 第24位:第16位是否有效的标志,程序根据它来决定是否增加火箭少女引用计数位的值
  • 第25位:是否拥有拷贝辅助函数
  • 第26位:是否拥有block析构函数
  • 第27位:标志是否有垃圾回收
  • 第28位:标志是否是全局block
  • 第30位:与BLOCK_USE_START相对,判断当前block是否拥有一个签名,用于runtime时动态调用
    但部分block则拥有Block_descriptor_2Block_descriptor_3结构这句话又该怎么去理解呢?请看下面的解释
static struct Block_descriptor_2 * _Block_descriptor_2(struct Block_layout *aBlock)
{if (! (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) return NULL;uint8_t *desc = (uint8_t *)aBlock->descriptor;desc += sizeof(struct Block_descriptor_1);return (struct Block_descriptor_2 *)desc;
}static struct Block_descriptor_3 * _Block_descriptor_3(struct Block_layout *aBlock)
{if (! (aBlock->flags & BLOCK_HAS_SIGNATURE)) return NULL;uint8_t *desc = (uint8_t *)aBlock->descriptor;desc += sizeof(struct Block_descriptor_1);if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE) {desc += sizeof(struct Block_descriptor_2);}return (struct Block_descriptor_3 *)desc;
}
  • 如果aBlock->flags & BLOCK_HAS_COPY_DISPOSE满足,则_Block_descriptor_2存在,反之则block没有_Block_descriptor_2这个结构
    • _Block_descriptor_2可以通过Block_descriptor_1内存偏移得到
  • 同理,aBlock->flags & BLOCK_HAS_SIGNATURE满足,则_Block_descriptor_3存在
    • _Block_descriptor_3可以通过Block_descriptor_2内存偏移得到

决定这两个结构是否存在的绝对因素其实就是Block_layoutflags

// Values for Block_layout->flags to describe block objects
enum {BLOCK_DEALLOCATING =      (0x0001),  // runtimeBLOCK_REFCOUNT_MASK =     (0xfffe),  // runtimeBLOCK_NEEDS_FREE =        (1 << 24), // runtimeBLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compilerBLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ codeBLOCK_IS_GC =             (1 << 27), // runtimeBLOCK_IS_GLOBAL =         (1 << 28), // compilerBLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATUREBLOCK_HAS_SIGNATURE  =    (1 << 30), // compilerBLOCK_HAS_EXTENDED_LAYOUT=(1 << 31)  // compiler
};

接下来就用汇编来看看block中的签名
_ NSGlobalBlock__签名(_ Block_copy进入时)
Pasted image 20230725164533.png
Pasted image 20230725164557.png

方法签名在lldb调试中使用po命令,查看block对象的地址
通过方法签名,可以在运行时获取 Block 的参数和返回值类型,帮助程序在调用 Block 时正确地处理数据。
通过方法签名,你可以在运行时动态地调用不同的方法或函数,而不需要提前确定要调用的具体方法。

  1. 回调机制:方法签名使得你可以将方法或函数作为参数传递给其他方法或函数,从而实现回调机制。

  2. 反射机制:方法签名在反射机制中发挥重要作用,它允许程序在运行时获取方法的信息,如方法名称、参数个数、参数类型、返回值类型等。

  3. 适配器模式:在设计模式中,方法签名的使用有助于实现适配器模式,从而使不同接口的方法能够相互调用。
    方法签名的含义可查看[[Type Encodings]]

  4. v: 返回值是 void 类型。

  5. 8@?: 参数部分的编码。

    • 8 代表参数的个数。
    • @ 代表第一个参数是一个对象类型。
    • ? 代表第二个参数是一个 Block 类型。
    • 0 代表没有其他参数。
      NSStackBlock
      Pasted image 20230725171421.png

NSMallocBlock
Pasted image 20230725171603.png

http://www.lryc.cn/news/107400.html

相关文章:

  • Flutter 图片选取及裁剪
  • C语言每日一题:11.《数据结构》链表分割。
  • 记一次Oracle归档日志异常增长问题的排查过程
  • Java设计模式——类之间的关系
  • Dockerfile构建Redis镜像
  • C高级DAY2
  • Linux 服务管理
  • 问题记录 1 页面初始化触发el-form必填校验
  • 后端整理(JVM、Redis、反射)
  • 1. CUDA中的grid和block
  • 宝存科技企业级固态硬盘解决方案助力企业应用性能提升
  • 《练习100》31~35
  • 额外题目第4天|132 673 841 127 684 657
  • HTTP 状态码的分类和含义
  • Linux Bridge(网桥)
  • 【数据结构】优先队列
  • 如何在 Ubuntu 22.04 下编译 StoneDB for MySQL 8.0 | StoneDB 使用教程 #1
  • AMEYA360:尼得科科宝旋转型DIP开关系列汇总
  • 为什么感觉 C/C++ 不火了?
  • 【Linux】在服务器上创建Crontab(定时任务),自动执行shell脚本
  • 内存分析工具之Mat
  • 【逗老师的PMP学习笔记】项目的运行环境
  • Rust- 模块
  • 【开源源码学习】
  • CNN-NER论文详解
  • 利用ChatGPT制作行业应用:哪些行业最受益
  • 【SA8295P 源码分析】60 - QNX Host 如何新增 android_test 分区给 Android GVM 挂载使用
  • Linux 用户和权限
  • 分布式应用:ELFK集群部署
  • Quartz使用文档,使用Quartz实现动态任务,Spring集成Quartz,Quartz集群部署,Quartz源码分析