3

最近我了解到如果我需要保留一个块对象,我应该复制该块,因为它是在堆栈上创建的。

然后我回顾了我的一些代码。我发现我正在做类似的事情:

@implementation MyView
...
-(void) addButton:(NSString *)title clickAction:(void ^(void)) action {
    [self.buttons addObject:@[ title, action ] ];
}
-(void) createButtons { ... }
...
@end

...

// Somewhere in my project:
-(void) init {
     MyView *view = [MyView new];
     [view addButton:@"OK"     clickAction:^{ NSLog(@"OK");     }];
     [view addButton:@"Cancel" clickAction:^{ NSLog(@"Cancel"); }];
}

基本上,我向 MyView 添加了一些按钮信息。在某些时候,MyView 将创建按钮。当按钮被点击时,MyView 会找出对应的 clickAction,并调用它。

奇怪的是,这个程序运行良好,没有异常,没有错误。

那么,为什么程序在不复制块对象的情况下运行呢?

其他信息:* iphone app (4.3 - 6.0) * 非 ARC * XCode 4.5

4

2 回答 2

7

在幕后,块实现由两部分组成:

  • 块的可执行代码,以及
  • 包含块中使用的变量值的数据结构

仅将块的第二部分放入堆栈并复制到堆内存中;第一部分被编译成程序的代码段,不会被复制。

由于您的块实现不引用周围范围内的任何变量,因此它们的块的数据部分是空的。这就是您的代码有效的原因:根本没有什么可复制的!但是,无论如何,您都应该添加块副本,否则对块代码的微小更改会破坏您的应用程序,而编译器不会注意到任何事情。

于 2012-11-01T16:22:02.147 回答
0

编译器根据块的作用创建不同类型的块。如果一个块没有捕获任何变量,那么它可以用一个NSGlobalBlock(NSGlobalBlock只是一个函数指针) 来表示。我怀疑这就是正在发生的事情。

于 2012-11-01T16:24:12.070 回答