gpt4 book ai didi

objective-c - NSBlock 对象是如何创建的?

转载 作者:太空狗 更新时间:2023-10-30 03:18:59 25 4
gpt4 key购买 nike

我将通过声明我将要问的内容仅用于教育和可能的调试目的来作为这个问题的序言。

如何在 Objective C 运行时内部创建 block 对象?

我看到了所有代表各种 block 类型的类的层次结构,层次结构中最高的父类(super class),在 NSObject 之下,是 NSBlock。转储类数据表明它实现了 + alloc+ allocWithZone:+ copy+ copyWithZone:方法。其他 block 子类都没有实现这些类方法,这让我相信 NSBlock 负责 block 处理,这可能是错误的。

但是这些方法似乎在 block 的生命周期内的任何时候都不会被调用。我用自己的实现交换了实现并在每个实现中放置了一个断点,但它们从未被调用过。对 NSObject 的实现进行类似的练习给了我想要的东西。

所以我假设 block 是以不同的方式实现的?任何人都可以阐明此实现的工作原理吗?就算不能hook到block的分配和复制,也想了解一下内部实现。

最佳答案

tl;dr

编译器直接将 block 字面量翻译成结构体和函数。这就是为什么您看不到 alloc 调用的原因。


讨论

虽然 block 是成熟的 Objective-C 对象,但这一事实在它们的使用中很少暴露,使它们成为非常有趣的野兽。

第一个怪癖是 block 通常在堆栈上创建(除非它们是全局 block ,即不引用周围上下文的 block ),然后仅在需要时才在堆上移动。直到今天,它们是唯一可以在堆栈上分配的 Objective-C 对象。

可能由于分配中的这种怪异,语言设计者决定只允许通过 block 字面量创建 block (即使用 ^ 运算符)。通过这种方式,编译器可以完全控制 block 分配。

clang specification 中所述,编译器会自动为它遇到的每个 block 文字生成两个结构和至少一个函数:

  • block 文字结构
  • block 描述符结构
  • block 调用函数

例如对于文字

^ { printf("hello world\n"); }

在 32 位系统上,编译器将生成以下内容

struct __block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(struct __block_literal_1 *);
struct __block_descriptor_1 *descriptor;
};

void __block_invoke_1(struct __block_literal_1 *_block) {
printf("hello world\n");
}

static struct __block_descriptor_1 {
unsigned long int reserved;
unsigned long int Block_size;
} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };

(顺便说一句,该 block 符合全局 block 的条件,因此它将在内存中的固定位置创建)

所以 block 是 Objective-C 对象,但以低级方式:它们只是带有 isa 指针的结构。虽然从正式的角度来看它们是 NSBlock 的具体子类的实例,但 Objective-C API 从未用于分配,所以这就是为什么你看不到 alloc 调用:编译器将文字直接翻译成结构。

关于objective-c - NSBlock 对象是如何创建的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20134616/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com