Objective c 没有复制的iOS块对象?

Objective c 没有复制的iOS块对象?,objective-c,ios,block,Objective C,Ios,Block,最近我了解到,如果需要保留块对象,我应该复制块,因为它是在堆栈上创建的 然后我回顾了我的一些代码。我发现我在做这样的事情: @implementation MyView ... -(void) addButton:(NSString *)title clickAction:(void ^(void)) action { [self.buttons addObject:@[ title, action ] ]; } -(void) createButtons { ... } ... @en

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

然后我回顾了我的一些代码。我发现我在做这样的事情:

@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应用程序(4.3-6.0) *非弧
*XCode 4.5

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

  • 块的可执行代码,以及
  • 包含块中使用的变量值的数据结构
只有块的第二部分被放置在堆栈上并复制到堆内存中;第一部分编译为程序的代码段,不会被复制


由于块实现不引用周围范围中的任何变量,因此其块的数据部分为空。这就是你的代码工作的原因:根本没有东西可以复制!但是,您还是应该添加块副本,因为否则,对块的代码进行一个小的更改就会中断应用程序,而编译器不会注意到任何东西。

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

我很确定代码仍然可以工作,无论块有多复杂,因为
action
被放置在
NSArray
中,这将导致它被集合保留…@JodyHagins保留不是问题,堆栈上分配的主体超出范围将导致问题。当该方法存在时,在其内部创建的块将在内存的无效区域中结束。这就是为什么您需要将它复制到堆中。对-但是当NSArray保留它时,它会被复制到堆中。从那时起,NSArray中的对象将是堆版本,而不是原始堆栈块。如果对基于堆栈的块调用retain,它会将其复制到堆中,然后保留它。@JodyHagins我有理由相信,仅仅将
retain
发送到堆栈对象不足以生成堆栈副本。块会得到特殊处理。我已经很久没有使用非弧形块了,我想它会
Block\u copy
作为retain的一部分,因为它知道它在堆栈上(并且块在其他情况下会得到特殊处理)。。。但这将打破“保留必须返回相同实例”的定义。。。我甚至在发布最后一条评论之前做了一个小测试来证明自己。。。并且没有取消选中ARC框。。。我将删除我的帖子,并留下这条评论,以确认我是一个白痴。。。并承诺永远不会回答另一个非ARC特定的问题:-)谢谢,看来你和@dasblinkenlight有着相同的观点。我将接受dasblinkenlight的答案,因为他的答案更详细。