您对通知和代表的替代方案的看法:信号?

时间:2011-01-24 19:15:51

标签: objective-c events delegates notifications signals

SO告诉我这个问题是主观的,可能会被关闭。这确实是主观的,因为我要求经验丰富的Objective-C开发人员提出意见。我应该在其他地方张贴这个吗?请告知。


Objective-C相当新,尽管对编写OOP代码的概念非常有信心,但我从一开始就一直在努力应对NSNotification与Delegate的困境。我仅就这个问题发表了一些问题。我想,我确实得到了要点。通知在全球范围内广播,因此不应用于通知密切相关的对象。存在代表将任务移交给代表委托对象的其他对象。虽然这可以用于密切相关的对象,但我发现工作流程冗长(新类,新协议等),单独的“委托”一词让我想起了军队和老板,总的来说让我感到不安。 / p>

我来自哪里(AS3)有一些叫做事件的东西。他们在代表和NSNotifications之间走了一半,并且几乎统治了闪电通知的世界,直到最近,罗伯特·彭纳先生出现并表达了他对事件的不满。因此,他编写了一个现在广泛用于AS3社区的库,名为Signals。受Qt中的C#事件和信号/插槽的启发,这些信号实际上是对象的属性,您可以从外部访问并添加侦听器。你可以用信号做更多的事情,但就其核心而言,就是这样。

因为这个概念非常简陋,所以我试了一下,在Objective-C中编写了自己的信号类。 I've gisted Signal.h/.m here

使用它来通知A类中B类事件的A类的方法可能如下所示:

// In class b, assign a Signal instance to a retained property:
self.awesomeThingHappened = [[[Signal alloc] init] autorelease];

// In class a, owner of class b, listen to the signal:
[b.awesomeThingHappened add:self withSelector:@selector(reactToAwesomeThing)];

// And when something actually happens, you dispatch the signal in class b:
[self.awesomeThingHappened dispatch];

// You might even pass along a userInfo dictionary, your selector should match:
[self.awesomeThingHappened dispatchWithUserInfo:userInfo];

我希望它遵守正确的内存管理规则,但是当信号deallocs时,它应该自动删除所有侦听器并静默消失。像这样的信号不应该是通知和授权的通用替代品,但是有很多紧密的反制情况,我觉得Signal比其他两个更干净。

我对stackoverflow的问题是你怎么看待这样的解决方案?如果你的一个实习生把它放进去,你会立即从你的项目中删除吗?如果他已完成实习,你会解雇你的员工吗?或者可能已经有类似但更加宏伟的东西,你可以使用它?

感谢您的时间,EP。


编辑:让我举一个具体的例子,说明我在iOS项目中如何使用它。

考虑这种具有嵌套所有权的四种对象类型的场景。有一个视图控制器拥有一个窗口管理器,拥有几个窗口,每个窗口拥有一个带控件的视图,其中包含一个关闭按钮。这里可能存在设计缺陷,但这不是示例的重点:P

现在,当点击关闭按钮时,手势识别器会触发窗口对象中的第一个选择器。这需要通知窗口管理器它正在关闭。然后窗口管理器可以决定是否出现另一个窗口,或者窗口是否完全隐藏,此时视图控制器需要获得一个凸起以启用主视图上的滚动。

从窗口到窗口管理器,从窗口管理器到视图控制器的通知是我现在用Signals实现的。这可能是委托的情况,但对于“近距离”行动,创建两个委托协议似乎很冗长。另一方面,由于这些对象的耦合定义非常明确,因此NSNotifications似乎也不是这样。 KVO也没有真正的价值变化,因为它只是一个按钮。听取某种“隐藏”状态只会让我在重新打开窗口时重置该标志,这使得它更难理解并且容易出错。

4 个答案:

答案 0 :(得分:2)

好吧,在对答案和评论进行腌制之后,我想我已经得出结论,我从AS3借来的Signal类,在Objective-C / Cocoa中几乎没有理由存在。 Cocoa中有几种模式涵盖了我想用Signal类覆盖的使用范围。对于经验丰富的Cocoa开发人员来说,这似乎是微不足道的,但对我而言,很难让频谱完整。

我试图把它简明扼要地说,但如果我错了,请纠正我。

目标 - 动作

仅用于通知您的应用程序用户交互(主要是触摸)。从我所看到和阅读的内容来看,没有办法“借用”目标行动系统供你自己使用

KVO(键值观察)

在可访问对象中的值更改时接收通知非常有用。对通知没有附加值的特定事件(如计时器事件或接口后续事件)不太有用。

NSNotification

非常有用,可以在值不可更改的对象中更改值或发生其他事件时接收通知。由于通知中心的广播性质,这不太适合对象直接引用另一个对象的情况。

与其他三个代码相比,占用的代码最多,但是当其他三个代码不同时,它也是最合适的。当一个对象应该被告知另一个对象中的特定事件时,请使用此对象。不应仅仅因为访问所有者对象的方法而滥用代表。坚持使用'应该','将'和'做'等方法。

信号

这是一个有趣的实验,但我主要用于经典授权情况。我还用它来规避链接的代理(c代表b,b代表a,在哪里启动应该使它成为c的事件)而不想诉诸NSNotification。

我仍然认为应该有一个更优雅的解决方案,但现在我会 坚持现有的框架。如果有人有更正或其他通知概念,请告诉我。谢谢你的帮助!

答案 1 :(得分:1)

这是一个有趣的想法,但我想我看不出是什么让它与Cocoa的通知中心截然不同。比较和对比:

self.awesomeThingHappened = [[[Signal alloc] init] autorelease];                  // Your signals library
                                                                                  // Cocoa notifications (no equivalent code)

[b.awesomeThingHappened add:self withSelector:@selector(reactToAwesomeThing)];    // Your signals library
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(reactToAwesomeThing:)
                                             name:@"AwesomeThingHappened"
                                           object:n];                             // Cocoa notifications

[self.awesomeThingHappened dispatch];                                             // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:@"AwesomeThingHappened"
                                                    object:self];                 // Cocoa notifications

[self.awesomeThingHappened dispatchWithUserInfo:userInfo];                        // Your signals library
[[NSNotificationCenter defaultCenter] postNotificationName:@"AwesomeThingHappened"
                                                    object:self
                                                  userInfo:userInfo];             // Cocoa notifications

所以,好的。我不认为你想说的是,逐行,Cocoa的Signals库是不同的;相反,该论点认为它是耦合的术语,它不像代表那么紧,但不像通知那样松散。为此,我想我不知道它有多必要?我想我可以看到有必要说“这个对象'A'在很大程度上依赖于'B',但不需要紧密耦合”,但说实话,这似乎是一种罕见的情况。 / p>

无论如何,NSNotificationCenter及其同类以及代表在Cocoa应用程序中都非常标准。我总是使用经验法则,如果你偏离标准,甚至是事实上的标准,你应该有充分的理由。如果您有充分的理由既不使用NSNotificationCenter也不使用委托,那么您可能有充分的理由使用此信号设置。 (顺便说一句,我对将通知和代表联系起来犹豫不决 - 他们每个人都有一个角色并且因各种原因而存在。)

没有具体的用例,很难说更多。我倾向于说,“嘿,它以一种令人讨厌的方式看起来很酷,但看起来它已经填满了已经通知的角色。”您是否有任何具体的用例?

答案 2 :(得分:0)

  

您如何看待这样的解决方案?

我真的没看到有什么好处。对我而言,它似乎是目标/动作+通知的组合(您可以为单个通知事件设置多个目标/操作,但是t / a对已注册到对象本身而不是全局通知中心)。实际上,除了KVO仅限于可观察的属性之外,它更像是键值观察,但

  

如果你的一个实习生把它放进去,你会立即从你的项目中删除它吗?

没有。它不是代码。事实上,它似乎有点整洁。但我只是没有看到明显的好处。

  

如果他的员工已经完成实习,你会解雇他吗?

当然不是。你不会因为编写好的代码而解雇人。

  

是否可能已经有类似的东西,但你会使用更多的东西呢?

如果您真的想要做到这一点,请更改API以使用块。然后你可以这样做:

[object dispatchOnAwesomeThingHappened:^{
  NSLog(@"holy cow, something awesome just happened!");
}];

然而,再一次,你只能对对象明确“发送”的内容做出反应。如果您可以在任意方法调用之前和/或之后立即附加内容,那将更加简洁。如果您对此感兴趣,那么我会查看Aspect Objective-C on github

答案 3 :(得分:0)

我认为 是NSNotifications和Delegates之间的差距。和KVO has the worst API in all of Cocoa

至于NSNotificationCenter,这里有一些问题:

  • 它容易出现拼写错误
  • 很难跟踪给定对象的观察者,因此难以调试
  • 非常详细
  • 您只能在字典中传递通知数据,这意味着您不能使用弱引用或结构,除非您将它们包装起来。 (见:非常详细)
  • GCD不相称:对队列的支持有限(仅限数据块)

所以肯定需要更好的东西。

我创建了my own observable class,我在每个项目中使用它。另一种方法是使用ReactiveCocoa' RACSignal