iOS——Block签名

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

objc 复制代码
#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_DISPOSE
      BlockCopyFunction copy;
    BlockDisposeFunction dispose;
};

#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {
    // requires BLOCK_HAS_SIGNATURE
    const char *signature;
    const char *layout;     // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};

struct Block_layout {
    void *isa;
    volatile int32_t flags; // contains ref count
    int32_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结构这句话又该怎么去理解呢?请看下面的解释
objc 复制代码
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

objc 复制代码
// Values for Block_layout->flags to describe block objects
enum {
    BLOCK_DEALLOCATING =      (0x0001),  // runtime
    BLOCK_REFCOUNT_MASK =     (0xfffe),  // runtime
    BLOCK_NEEDS_FREE =        (1 << 24), // runtime
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
    BLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ code
    BLOCK_IS_GC =             (1 << 27), // runtime
    BLOCK_IS_GLOBAL =         (1 << 28), // compiler
    BLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE  =    (1 << 30), // compiler
    BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31)  // compiler
};

接下来就用汇编来看看block中的签名

_ NSGlobalBlock__签名(_ Block_copy进入时)

方法签名在lldb调试中使用po命令,查看block对象的地址

通过方法签名,可以在运行时获取 Block 的参数和返回值类型,帮助程序在调用 Block 时正确地处理数据。

通过方法签名,你可以在运行时动态地调用不同的方法或函数,而不需要提前确定要调用的具体方法。

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

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

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

    方法签名的含义可查看[[Type Encodings]]

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

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

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

NSMallocBlock

相关推荐
Lecxcy_Kastreain3 分钟前
如何自适应 MacOS
macos
坏小虎1 小时前
Expo 快速创建 Android/iOS 应用开发指南
android·ios·rn·expo
光影少年2 小时前
Android和iOS原生开发的基础知识对RN开发的重要性,RN打包发布时原生端需要做哪些配置?
android·前端·react native·react.js·ios
北京自在科技2 小时前
Find My 修复定位 BUG,AirTag 安全再升级
ios·findmy·airtag
简单点了2 小时前
mac安装node环境
macos
简单点了3 小时前
mac安装vm装win11虚拟机
macos
Digitally3 小时前
如何不用 USB 线将 iPhone 照片传到电脑?
ios·电脑·iphone
todoitbo3 小时前
装了 QClaw 之后,我卸掉了好几个 Mac 软件
人工智能·macos·ai·软件·openclaw·qclaw
總鑽風12 小时前
搭建Spring Boot + ELK日志平台,实现可视化日志监控
spring boot·elk·macos
Sim148015 小时前
iPhone将内置本地大模型,手机端AI实现0 token成本时代来临?
人工智能·ios·智能手机·iphone