2010-08-03 29 views
51

我经常发现自己正在编写可以在我的项目中重复使用的“实用程序”类。目标C:模块与选择器与协议

例如,假设我有一个“地址簿”视图。我可能想要使用我的地址簿来选择发送电子邮件的人员,或者将其添加到会议请求中的人员。

我开发了这个视图控制器,以便电子邮件控制器和会议控制器都可以使用某种回调机制来让调用者知道用户是否从地址簿中选择了某人,或者他们取消了。

看来基本上有四种(合理的)方法可以在这种情况下使用;

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

  • 在AddressBookController上创建一个“非正式”AddressBookDelegate协议和一个相应的委托属性,但委托属性的类型为“id”,并在运行时检查“respondsToSelector:”以查看委托实现我们需要的方法(看起来像大多数框架的东西已经开始这样)。

  • 传递AddressBookController一个表示委托的id,以及两个SEL,它们指定在用户选择用户或取消请求时调用的方法。我看到的好处是;假设一个控制器支持发送电子邮件和建立会议(在这个例子中,我知道这似乎是不好的设计......但可以想象一个更普遍的情况,这对于公共事业类似乎是完全合理的) - 在这种情况下,你可以根据您是否将用户添加到电子邮件中或将用户添加到会议中,传递AddressBookController不同的SEL ...对iVar的巨大改进来指示控制器的“状态”。

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

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

我希望有更多有经验的StackOverflow社区成员比我能帮助他们对这个主题的想法。

+0

我希望人们对他们同意的现有答案投票。我会在几天内给出答案,谁拥有最多的选票。 – Steve 2010-08-03 02:12:20

回答

27

“传统”的方式是使用协议。在@protocol被添加到语言之前使用了非正式的语言,但那是在我的时间之前,至少在过去的几年中,非正式协议已经被泄露,特别是@optional说明​​符。至于通过两个SEL的'代表',这似乎比宣布一个正式的协议更丑陋,而且对我来说通常看起来并不正确。块是非常新的(尤其在iOS上),随着这些事情的发展,虽然我们还没有看到大量的文档/博客以最好的尝试和真实的风格,但我喜欢这个想法,而这似乎是东西块最适合:整洁的新控制流结构。

基本上我想说的是,这些方法中的每一个都随着年龄的不同而变化,除了风格,没有一个比上一个更好,这显然是非常重要的,最终是为什么这些东西都是创建。基本上,你可以选择你认为最舒服的东西,它应该是块或者是一个正式的协议,而且你的困惑最可能来自冲突的源头,因为它们是在不同的时间编写的,但从时间的角度来看,它是清楚地看到哪些取代了其他人。

[Controller askForSelection:^(id selection){ 
    //blah blah blah 
} canceled:^{ 
    //blah blah blah 
}]; 

可能是一个很大的地狱不是定义两个额外的方法更简洁,并为他们的协议(正式或其他方式)或传递的SEL并将它们存储在高德等

+10

请请每个方法只使用一个块(并使其成为最后一个参数)。如果你需要两个,创建一个封装他们的类。想象一下,如果所有的等等等等都完全扩展,会发生什么。 – bbum 2010-08-03 03:50:11

+2

如果您将它们存储在要传入的变量中,而不是使用块文字,那么它就不那么糟糕。但是,是的,将它们分开是明智的风格。 – 2010-08-03 04:53:15

+14

@bbum - 我尊重你(我非常非常尊重你)我认为每个方法规则的一个块完全基于样式,并且在方法中使用两个块看起来不比if-else语句更差。如果你认为if-then语句是丑陋的,那么是的,这也会显得很丑陋,因为除了[s,] s,^ s和s之外,它的结构完全像if-else。 (它甚至有相同的想法,如果是的话(选择了某些东西),然后做一些事情,如果不是它下面的块。) – 2010-08-03 12:59:14

16

我会只需要你的第一个方法。这在可可中是一种可靠和真实的模式,似乎非常适合你正在做的事情。

的其他方法需要注意几点:

  1. 非正式协议 - 我实在不明白这样做了正式协议的任何优势。自从正式的协议获得方法以来,非正式协议的效用要少得多。
  2. 传递SELs - 我不认为这是Cocoa中的一个既定模式。我个人并不认为它比代表方式更好,但如果它更符合你的想法,那就去做吧。你并没有真正摆脱状态;你只是变成了别的东西。就个人而言,我宁愿有一个我可以设置和检查而不必使用选择器类型的伊娃。
  3. 传递块 - 这是一种新时代的方法,它有一些优点。我认为你需要小心,因为在我看来,它并不能很好地扩展。例如,如果NSTableView的委托和数据源方法都是块,我个人觉得有点烦人。想象一下,如果你想设置10个不同的块,你的-awakeFromNib(或其他)方法会很大。在这种情况下,单独的方法似乎更合适。但是,如果你确信你永远不会超越,比如两种方法,那么块方法似乎更合理。