Leo*_*ica 14 objective-c objective-c-runtime objective-c-blocks
我将在这个问题的前言中说明我要问的是教育和可能的调试目的.
如何在Objective C运行时内部创建块对象?
我看到所有类代表各种块类型的类的层次结构,下面的层次结构中最高的超类NSObject是NSBlock.倾销类的数据显示,它实现了+ alloc,+ allocWithZone:,+ copy和+ copyWithZone:方法.其他块子类都没有实现这些类方法,这使我相信(可能是错误的NSBlock)负责块处理.
但是这些方法似乎在一个块的生命周期中的任何时候都不会被调用.我用自己的实现交换了实现并在每个实例中放置了一个断点,但是它们永远不会被调用.用NSObject实现做类似的练习给了我我想要的东西.
所以我假设块以不同的方式实现?任何人都可以了解这种实施方式的工作原理?即使我不能挂钩分配和复制块,我想了解内部实现.
Gab*_*lla 13
编译器直接将块文字转换为结构和函数.这就是你没有看到alloc电话的原因.
虽然块是完全成熟的Objective-C对象,但这个事实很少暴露在它们的使用中,使它们成为非常有趣的野兽.
第一个怪癖是通常在堆栈上创建块(除非它们是全局块,即没有引用周围上下文的块),然后仅在需要时才在堆上移动.到目前为止,它们是唯一可以在堆栈上分配的Objective-C对象.
可能由于其分配中的这种奇怪,语言设计者决定仅通过块文字(即使用^运算符)来允许块创建.通过这种方式,编译器可以完全控制块分配.
正如clang规范中所解释的,编译器将自动为它遇到的每个块文字生成两个结构和至少一个函数:
例如对于文字
^ { printf("hello world\n"); }
Run Code Online (Sandbox Code Playgroud)
在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 };
Run Code Online (Sandbox Code Playgroud)
(顺便说一句,该块有资格作为全局块,因此它将在内存中的固定位置创建)
所以块是Objective-C对象,但是以低级方式:它们只是带有isa指针的结构.虽然从形式上看它们是具体子类的实例NSBlock,但Objective-C API从不用于分配,因此您没有看到alloc调用:文本被编译器直接转换为结构.
如其他答案中所述,块对象直接在全局存储(由编译器)或在堆栈(由编译的代码)上创建.它们最初不是在堆上创建的.
块对象类似于桥接的CoreFoundation对象:Objective-C接口是底层C接口的封面.块对象的-copyWithZone:方法调用该_Block_copy()函数,但有些代码_Block_copy()直接调用.这意味着断点-copyWithZone:将无法捕获所有副本.
(是的,你可以在普通的C代码中使用块对象.有一个qsort_b()函数和一个atexit_b()函数,呃,可能就是它.)
| 归档时间: |
|
| 查看次数: |
3001 次 |
| 最近记录: |