我正在尝试减少仪式并出于学术上的好奇心我想知道如果没有.m文件中定义的IBAction方法如何在每次发生Interface Builder有线操作(如按下按钮)时使用闭包,我都知道如何执行以下操作。你可以说我想暗示下面的cancelButtonPress方法,而不是必须定义它。 UIViewController子类或存储在类别中的一些魔法是完全可以接受的。
@interface MyViewController : UIViewController
{
void(^doOnCancel)(void);
}
@property (nonatomic, copy) void(^doOnCancel)(void);
- (IBAction)cancelButtonPress:(id)sender;//I want this gone!
@end
我尝试在属性和变量中将void
更改为IBAction
但没有运气。
编辑:替代模式也可以减少使用闭包操作的重复次数。
赏金是为了一个良好的模式,允许封闭被任意地用于服务IB中定义的行动,以一种可用于减少仪式的方式。到目前为止,“不能这样做”的评论可能会也可能不正确。
答案 0 :(得分:4)
Ahruman的方法很好,但它可能过于依赖运行时。除了性能问题之外,如果其他人想要同时使用运行时,Swizzling和使用initialize
更容易受到错误的影响。我建议使用C宏。
在类的顶部(或任何地方,确实)定义这些宏:
typedef void(^BlockAction)(id sender);
#define BlockActionProperty(ACTION) @property (copy) BlockAction ACTION;\
- (IBAction) ACTION:(id)sender;
#define BlockActionSynthesize(ACTION) @synthesize ACTION;\
- (IBAction) ACTION:(id)sender {\
if (ACTION) ACTION(sender);\
}
现在要创建一个新操作,您需要做的就是用以下内容替换标题中的@property ...
:(例如):
BlockActionProperty(testAction);
并在实施中“合成”它:
BlockActionSynthesize(testAction);
如果你想覆盖它并使用普通的动作方法,你可以随时合成并照常执行动作。
这比在运行时更快(并且在我看来更干净),并且因为定义了IBAction
,所以Interface Builder可以“看到”它的定义。
答案 1 :(得分:3)
在这里,您可以将任何块类型属性用作操作:http://gist.github.com/589740
正如你所说,它是学术上的好奇心。我真的不建议将它用于实物。
此外,它并不严格符合您的要求,因为该操作是在未实现的类别中声明的。这纯粹是为了使Interface Builder可以通过扫描标头自动找到它。您可以删除它并在IB的检查器中手动添加操作,但这对我来说似乎是一种损失,因为保持它正确同步是更难的。
答案 2 :(得分:1)
如果不采用“将cancelButtonPress:
中通常存在的代码放在forwardInvocation:
中”,则不能。 Interface Builder操作发送消息。调用块不能是动作消息的直接结果。
可以扩展控件,使其调用块而不是向控制器发送正常的操作方法,但这需要更多的代码,并且它不会神奇地使Interface Builder支持它。