目标C:块与选择器与协议

Ste*_*eve 51 objective-c

我经常发现自己编写的"实用程序"类可以在整个项目中重复使用.

例如,假设我有一个"地址簿"视图.我可能想使用我的地址簿来选择向谁发送电子邮件,或者可能是谁被添加到会议请求中.

我开发了这个视图控制器,因此它可以被电子邮件控制器和会议控制器使用,具有某种回调机制,让调用者知道用户已完成从地址簿中选择某人,或者他们已取消.

在这种情况下,似乎基本上有四种(合理的)方法;

  • 在AddressBookController上创建"AddressBookDelegate"协议和相应的委托属性.然后使用协议中定义的消息来传达结果(类似于UIActionSheetDelegate).

  • 在AddressBookController上创建一个"非正式""AddressBookDelegate"协议和相应的委托属性,但委托属性的类型将是"id",并将在运行时使用"respondsToSelector:"检查委托是否实现了我们的方法要求(似乎大多数框架的东西已经开始这样).

  • 传递AddressBookController一个代表委托的id,以及两个SEL,它们指定当用户选择用户或取消请求时要调用的方法.我看到的好处是; 假设一个控制器支持同时发送电子邮件和设置会议(我知道在这个例子中看起来像是糟糕的设计...但是可以想象一个更通用的情况,这对于实用程序类来说这似乎是完全合理的) - 在这种情况下你可以传递AddressBookController不同的SEL,具体取决于您是将用户添加到电子邮件,还是将用户添加到会议......对iVar的巨大改进表明控制器的"状态".

  • 传递AddressBookController两个块; 一个在用户从地址簿中选择某人时运行,另一个在用户取消请求时运行.

这些块对我来说非常有用,而且更加优雅,我发现自己几乎不知道何时不使用它们.

我希望StackOverflow社区中更有经验的成员比我能帮助他们对这个主题有所了解.

Jar*_*tar 27

执行此操作的"传统"方法是使用协议.在将@protocol添加到语言之前使用了非正式的,但这是在我的时间之前,并且至少在过去的几年里,不鼓励使用非正式协议,特别是考虑到@optional说明​​符.至于通过两个SEL的'委托',这似乎比宣布一个正式的协议更难看,而且对我来说似乎并不合适.块是非常新的(特别是在iOS上),随着这些事情发生,虽然我们还没有看到大量的文档/博客上最好的尝试和真实的风格,我喜欢这个想法,这似乎是一个事物块最适合:整洁的新控制流结构.

基本上我要说的是,这些方法中的每一种都有所不同,没有一种比最后一种更好,除了风格,这显然非常重要,并且最终是为什么这些东西都被创造了.基本上,请选择您认为最新的东西,它应该是块或正式协议,并且您的混淆最有可能来自阅读冲突的来源,因为它们是在不同时间编写的,但是从时间上看,它是清楚地看到哪些取代了其他人.

[Controller askForSelection:^(id selection){
  //blah blah blah
} canceled:^{
  //blah blah blah
}];
Run Code Online (Sandbox Code Playgroud)

可能比定义两个额外的方法,以及它们的协议(正式或其他方式)或传递SEL并将它们存储在ivars等中更简洁.

  • @bbum - 非常尊重(我非常非常尊重你)我认为每个方法规则的一个块完全基于样式,并且在方式中使用两个块看起来并不比if-else语句差.如果你认为if-then语句是丑陋的,那么这也会显得很丑陋,因为除了[s,] s,^ s和:s之外,它的结构与if-else完全相同.(它甚至有同样的想法,如果是(选择了某些东西)然后用它做一些事情,如果不做它下面的块.) (14认同)
  • 请拜托,每个方法只使用一个块(并将其作为最后一个参数).如果您需要两个,请创建一个封装'em的类.想象一下,如果所有的等等等等都完全扩大了会发生什么. (10认同)
  • 如果将它们存储在变量中以传入而不使用块文字,那就不那么糟糕了.但是,是的,将它们分开是更好的风格. (2认同)

kpe*_*yua 17

我会采用你的第一种方法.它在Cocoa中是一个久经考验的模式,似乎非常适合你正在做的事情.

关于其他方法的一些评论:

  1. 非正式协议 - 我没有看到在正式协议上做这件事有什么好处.自从正式协议获得@optional方法以来,非正式协议的效用要少得多.
  2. 传递SEL - 我不认为这是Cocoa的既定模式.我个人不会认为它比代表方法更好,但如果它更适合你的想法,那就去吧.你并没有真正摆脱国家; 你只是在转变成别的东西.就个人而言,我更喜欢有一个我可以设置和检查的ivar,而不必使用选择器类型.
  3. 传递积木 - 这是一种新时代的方法,它有一些优点.我认为你需要小心,因为在我看来,它并不能很好地扩展.例如,如果NSTableView的委托和数据源方法都是块,我个人会觉得有点烦人.想象一下,如果你想设置10个不同的块,你的-awakeFromNib(或其他)方法会非常大.在这种情况下,个别方法似乎更合适.但是,如果您确定自己永远不会超越两个方法,那么块方法似乎更合理.