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

Objective c 目标C:块与选择器与协议,objective-c,Objective C,我经常发现自己编写的“实用程序”类可以在整个项目中重复使用 例如,假设我有一个“地址簿”视图。我可能想使用我的通讯簿来选择谁收到电子邮件,或者谁被添加到会议请求中 我将开发这个视图控制器,以便电子邮件控制器和会议控制器都可以使用它,并使用某种回调机制让调用者知道用户已完成从通讯簿中选择某人,或者他们已取消 在这种情况下,基本上有四种(合理的)方法 在AddressBookController上创建“AddressBookDelegate”协议和相应的委托属性。然后使用协议中定义的消息传递结果(

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

例如,假设我有一个“地址簿”视图。我可能想使用我的通讯簿来选择谁收到电子邮件,或者谁被添加到会议请求中

我将开发这个视图控制器,以便电子邮件控制器和会议控制器都可以使用它,并使用某种回调机制让调用者知道用户已完成从通讯簿中选择某人,或者他们已取消

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

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

  • 在AddressBookController上创建“非正式的”“AddressBookDelegate”协议和相应的委托属性,但委托属性的类型将为“id”,并在运行时使用“respondsToSelector:”检查委托是否实现了我们需要的方法(看起来大部分框架的东西都开始这样做了)

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

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

这些积木对我来说非常有用,而且更加优雅,我发现自己几乎对什么时候不使用它们感到困惑


我希望StackOverflow社区中比我更有经验的成员能够帮助他们思考这个话题。

传统的方法是使用协议。非正式协议在@protocol被添加到语言之前就已经使用,但那是在我的时代之前,至少在过去几年非正式协议已经被使用couraged,特别是考虑到@optional说明符。对于通过两个SEL的“委托”,这似乎比声明正式协议更难看,而且在我看来通常不正确。块非常新(特别是在iOS上),随着这些事情的发展,虽然我们还没有看到大量关于最佳尝试和真实风格的文档/博客,但我喜欢这个想法,这似乎是块最适合的事情之一:整洁的新控制流结构

基本上,我想说的是,每一种方法都随着年龄的变化而变化,除了风格之外,没有一种方法比上一种更好,这显然是非常重要的,这也是为什么每一种方法都被创造出来的原因。基本上,用你觉得舒服的最新的方法,要么是块,要么是正式的协议,一个你的困惑很可能来自于阅读相互冲突的资料,因为它们是在不同的时间写的,但随着时间的推移,很明显会看到哪些资料取代了其他资料

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

可能比定义两个额外的方法和它们的协议(正式的或其他的)或传递SEL并将它们存储在IVAR中等要简洁得多。

我同意你的第一种方法。这是一种在Cocoa中久经考验的真实模式,似乎非常适合你正在做的事情

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

  • 非正式协议-我真的不认为这样做比正式协议有什么好处。自从正式协议获得了
    @可选的
    方法以来,非正式协议的效用要小得多
  • 我不认为这是可可的既定模式。我个人认为它不会比代表方法更好,但是如果它更适合你的想法,那就去做吧。你不是真的摆脱了状态;你只是转变成了别的东西。不必使用选择器类型的集合和检查
  • 传递块-这是一种新时代的方法,它有一些优点。但我认为你需要小心,因为在我看来,它的伸缩性不太好。例如,如果NSTableView的委托和数据源方法都是块,我个人会觉得这有点烦人。想象一下,如果你想设置10不同的块,您的
    -awakeFromNib
    (或其他)方法会非常大。在这种情况下,单独的方法似乎更合适。但是,如果您确定永远不会超过(比如)两种方法,那么块方法似乎更合理

  • 我希望人们投票支持他们同意的任何现有答案。我会在几天内把答案给投票最多的人。请,请,请,请,每个方法只使用一个区块(并将其作为最后一个论点)。如果您需要两个,请创建一个封装它们的类。想象一下,如果所有这些废话都被完全扩展,会发生什么。如果您将它们存储在变量中以传入,而不使用块文本,这并没有那么糟糕。但是,是的,从样式上讲,将它们分开要好得多。@bbum-恕我直言(我非常非常尊重您)我认为“每个方法一个块”规则完全基于样式,以这种方式使用两个块看起来并不比