Objective c 复制块-复制基元类型的捕获变量
我搜索了几个关于复制块的主题,但没有找到我感兴趣的信息 当我们定义一个块时,我们有机会从它的封闭范围捕获变量。由于块存储在堆栈上,变量由值捕获,因此这里一切都很清楚:Objective c 复制块-复制基元类型的捕获变量,objective-c,objective-c-blocks,Objective C,Objective C Blocks,我搜索了几个关于复制块的主题,但没有找到我感兴趣的信息 当我们定义一个块时,我们有机会从它的封闭范围捕获变量。由于块存储在堆栈上,变量由值捕获,因此这里一切都很清楚: 对于基元类型,我们获取附加变量(也在堆栈上本地化),例如一些常量int,其值与原始int变量相同 对于指针,我们获取一个特定指针的副本,这样指针对象的引用计数就增加了1 现在,我不知道当我们将一个块从堆栈移动(复制)到堆时会发生什么。对于捕获的指针,它很简单——我们获取这些指针的副本。但捕获的基元类型变量会发生什么情况?堆上的
- 对于基元类型,我们获取附加变量(也在堆栈上本地化),例如一些常量int,其值与原始int变量相同
- 对于指针,我们获取一个特定指针的副本,这样指针对象的引用计数就增加了1
有人能告诉我,它是如何深入工作的吗?或者我在某个点上完全错了?我不太确定你在问什么,但也许简单解释一下块实际上是如何工作的可以澄清问题 块实际上是匿名类的实例。该类对每个捕获的变量都有一个ivar。当块被实例化时,所有捕获的变量都被复制到块上各自的IVAR中,该IVAR此时存储在堆栈上 将块复制到堆时,它会在堆上创建一个新的块对象,并将所有IVAR从堆栈块复制到堆块(此时还保留所有捕获的obj-c对象)。在指向原始值的指针和诸如此类的东西上没有混淆;堆上只有一个malloc'd区域包含所有捕获的值,就像任何其他obj-c对象一样
同时,块中的实际代码只是通过使用等价的
隐式块指针->backing\u ivar
来访问捕获的变量,与对象上的方法访问对象的ivar的方式完全相同。如果您学会使用Algol-68编程,那么您正在做的就是缺少一级指针。。。(ref loc
any?)
[以下内容稍作简化,以说明正在发生的事情的要点。]
声明变量时,请说:
int x;
您正在指示编译器找到一个能够存储int
表示形式的位置,并将该位置用于使用名称x
引用的值
跳过“查找”位,编译器构造一个内部表,即符号表,它将名称,x
映射到位置,并且位置可以表示为绝对地址(也称为指针)或从某个位置的偏移量,例如“堆栈上的第七个位置”。某些东西有时存储在计算机内部一个称为寄存器的特殊命名位置,例如,有一个寄存器存储堆栈指针,因此作为堆栈指针偏移量存储的变量作为与该寄存器中存储的值的偏移量进行定位
使用此表,查看x
的编译器可以确定存储x
值表示的地址
在机器指令级,读取或写入变量涉及使用带有地址的指令。因此,当你深入到实际的机器代码时,所有变量都是通过指针引用的
现在来谈谈你的案子。当您捕获示例x
integer变量时,编译器会在描述块的结构中为其分配一个位置。在符号表中,它为x
创建一个条目,并将其映射为“块变量区域中的第6个位置”。块变量区域的位置被安排在特定位置,可能是一个寄存器,就像上面的堆栈指针一样,然后机器指令找到x
的值作为该位置的偏移量
当块基于堆栈时,块变量区域将位于堆栈上,当它基于堆时,它将位于堆中,但由于它的位置在执行块之前存储在寄存器中,因此块的代码永远不需要更改-x
始终位于相对于块变量区域的相同偏移处
希望这一切都有意义 另一种“在幕后工作”的机制就是C结构成员访问。无论是在堆的堆栈上,块都是结构,每个捕获的变量都有成员(实际上它们也是Objective-C对象)。执行块时,将调用一个函数,该函数将指向该块的指针作为参数。此函数访问捕获的变量,如
blockPointer->capturedVar1
。blockPointer
此时指向何处并不重要,重要的是在结构中某处为捕获的变量分配了空间
您可能会发现这很有启发性:您可以在中找到血淋淋的细节 用一个例子来解释是最容易的。考虑这个简单的函数,包含一个简单的块:
void outerFunction() {
int x = 7;
dispatch_block_t block = ^{
printf("%d\n", x);
};
dispatch_sync(dispatch_get_main_queue(), block);
}
请记住,dispatch\u block\t
是voi的类型定义
struct Block_descriptor_1 {
unsigned long reserved;
unsigned long size;
const char *signature;
};
struct Block_literal_1 {
void *isa;
int flags;
int reserved;
void (*invoke)(void *);
struct Block_descriptor_1 *descriptor;
int x;
};
struct Block_descriptor_1 block_descriptor_1 = {
.size = sizeof(struct Block_literal_1),
.signature = "v4@?0"
};
void outerFunction_block_invoke(void *voidLiteral) {
struct Block_literal_1 *literal = (struct Block_literal_1 *)voidLiteral;
printf("%d\n", literal->x);
}
void outerFunction2() {
int x = 7;
struct Block_literal_1 block_literal_1 = {
.isa = __NSConcreteStackBlock,
.flags = BLOCK_HAS_SIGNATURE,
.invoke = outerFunction_block_invoke,
.descriptor = &block_descriptor_1,
.x = x
};
dispatch_sync(dispatch_get_main_queue(),
(__bridge dispatch_block_t)&block_literal_1);
}