如何在Objective-C中将块存储在属性中?

80

我想将Objective-C块存储在属性中以备后用。我不确定如何做,所以我进行了一些谷歌搜索,关于这个主题的信息非常少。但最终我还是找到了解决方案,我认为值得与其他像我一样的新手分享。

最初我认为我需要手动编写属性来使用Block_copy和Block_release。

幸运的是,我发现块是NSObjects-copy/-release等同于Block_copy/Block_release。因此,我可以使用@property (copy)来自动生成setter和getter。


1
可能是Can I use Objective-C blocks as properties?的重复问题。这个问题比那个问题更近。 - Richard J. Ross III
1
完整的示例代码,最新的,简单易懂地解释给初学者:https://dev59.com/Jm865IYBdhLWcg3wM7u0#20760583 - Fattie
1
对于新读者来说,这个非常古老的问题现在已经非常过时了。你只需要使用@property(copy)void (^doStuff)(void);,不需要更多或更少的东西。现在这个问题在Apple文档中已经被解释得非常清楚(包括原因)。这是再简单不过的答案了。实际上,整个问题现在已经没有什么历史价值了,因为你可以直接使用Swift。 - Fattie
3个回答

137

编辑:已更新以适应ARC

typedef void(^MyCustomBlock)(void);

@interface MyClass : NSObject

@property (nonatomic, copy) MyCustomBlock customBlock;

@end

@implementation MyClass

@end

MyClass * c = [[MyClass alloc] init];
c.customBlock = ^{
  NSLog(@"hello.....");
}

c.customBlock();

5
为什么在使用块时应该使用(nonatomic, copy),而不是(nonatomic, retain)?通常使用retain,但我找不到任何解释为什么要使用copy来处理块。 - Steve Potter
30
是的,戴夫,真的。我也可以搜索并看到那些东西。解释很含糊,比如你使用“复制”“使它们实际上存活在堆栈框架中。”我认为保留对象也可以做到这一点。但是,没有人解释块是如何在堆栈上分配的。然而,有一条评论链接到了一篇文章-http://cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html,解释得很好。请参见“块是有点奇怪的对象”。所以谢谢你! - Steve Potter
Dave - 我不确定是否应该特别使用“nonatomic”。(顺便说一下-不一定正确!!!-最新的Apple文档说你应该使用“copy”-结束。)很难看出性能是否重要,而且由于您在此处发布的帖子几乎是世界上唯一的参考资料,因此可能会有危险。对于这个不太清楚的问题有什么想法吗?谢谢! - Fattie
2
@JoeBlow 如果你担心从多个队列同时获取和设置属性的值,那么你只需要原子性。否则并不重要。 - Dave DeLong
3
我/我们在所有地方使用nonatomic。在我看来,它应该是默认设置。atomic会导致更大的二进制文件、较低的性能(所有访问器上都需要锁定),并且似乎承诺了线程安全——通常这必须在比属性访问器更高级别的层次上解决。 - Steven Kramer
显示剩余2条评论

104

如果不使用typedef,可以采用以下方式:

@property (copy, nonatomic) void (^selectionHandler) (NSDictionary*) ;


20
为了澄清,由于语法非常晦涩,这是一个名为“selectionHandler”的块属性,它需要一个NSDictionary*参数并返回void。 - Christopher Pickslay
我认为这并不难读,但我同意使用typedef会更美观。我倾向于为我通常要传递的参数编写一堆typedef:PFObjectBlock、PFStringBlock、PFArrayBlock、PFErrorBlock等。 - Besi
Would id、SEL和IMP允许进一步简化吗? - dklt

9

你可以在WWDC 2012会议的第712个会话中找到一个非常好的说明,从第83页开始。在ARC下保存代码块的正确方法如下:

@property(strong) my_block_type work;

注意保留环问题。解决方法是在不再需要时将块设置为nil:

self.work = nil;

2
只有在ARC下才能这样做。在MRC下这是错误的。但是copy在MRC和ARC下都可以正常工作。 - newacct
我认为复制在MRC的所有情况下都不会很好用,但在大多数情况下可能是可行的。 - Jorge Perez
你在MRC方面是正确的,但它不适用于ARC。抱歉,在我之前的评论中我想说的是ARC。 - Jorge Perez
非常有趣,你有关于ARC如何将块移出堆栈的任何想法吗? - MonsieurDart
__block yourClass* blockSelf = self。只能在“work”属性中使用blockSelf。 - MasterBeta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接