Objective-C库中回调的选择器或块 [英] Selectors or Blocks for callbacks in an Objective-C library

查看:182
本文介绍了Objective-C库中回调的选择器或块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发自定义 EventEmitter启发了Objective-C中的消息系统。对于听众提供回调,我们是否需要选择器为什么?

We're developing a custom EventEmitter inspired message system in Objective-C. For listeners to provide callbacks, should we require blocks or selectors and why?

作为开发人员使用第三方库,您最希望使用哪种?这似乎最符合苹果的轨迹,指南和做法?

Which would you rather use, as a developer consuming a third party library? Which seems most in line with Apple's trajectory, guidelines and practices?

我们正在开发品牌Objective-C中的新iOS SDK,其他第三方将用于将功能嵌入其应用程序。我们的SDK的很大一部分将需要将事件与听众进行通信。

We're developing a brand new iOS SDK in Objective-C which other third parties will use to embed functionality into their app. A big part of our SDK will require the communication of events to listeners.

有五种模式,我知道在Objective-C中进行回调,其中三种不是 t fit:

There are five patterns I know of for doing callbacks in Objective-C, three of which don't fit:


  • NSNotificationCenter - 不能使用,因为它不能保证订单观察者将被通知,因为没有办法让观察者阻止其他观察者收到事件(如 stopPropagation()将在JavaScript中)

  • 关键价值观察 - 似乎没有一个很好的建筑适合性,因为什么我们真的有消息传递,不总是状态绑定。

  • 代表和数据源 - 在我们的例子中,通常会有很多听众,而不是一个可以正确地被称为委托的听众。

  • NSNotificationCenter - can't use because it doesn't guarantee the order observers will be notified and because there's no way for observers to prevent other observers from receiving the event (like stopPropagation() would in JavaScript).
  • Key-Value Observing - doesn't seem like a good architectural fit since what we really have is message passing, not always "state" bound.
  • Delegates and Data Sources - in our case, there usually will be many listeners, not a single one which could rightly be called the delegate.

其中两个是竞争者:


  • 选择器 - 在这个模型下,调用者提供一个选择器和一个被集中调用来处理事件的目标。 li>
  • - 在iOS 4中引入,块允许功能传递,而不会被绑定到像观察者/选择器模式

  • Selectors - under this model, callers provide a selector and a target which are collectively invoked to handle an event.
  • Blocks - introduced in iOS 4, blocks allow functionality to be passed around without being bound to an object like the observer/selector pattern.

这似乎是一个深奥的意见问题,但我觉得有一个客观的正确答案,我只是在Objective-C中也没有经验来确定。如果这个问题有一个更好的StackExchange网站,请通过移动它来帮助我。

This may seem like an esoteric opinion question, but I feel there is an objective "right" answer that I am simply too inexperienced in Objective-C to determine. If there's a better StackExchange site for this question, please help me by moving it there.

我们选择作为为我们的事件处理程序指定回调的方法。我们基本上对此选择感到满意,并且不打算删除基于块的监听器支持。它有两个显着的缺点:内存管理和设计阻抗。

We chose blocks as the means of specifying callbacks for our event handlers. We're largely happy with this choice and don't plan to remove block-based listener support. It did have two notable drawbacks: memory management and design impedance.

块最容易使用在栈上通过将它们复制到堆来创建长寿命的块会引起有趣的内存管理问题。

Blocks are most easily used on the stack. Creating long-lived blocks by copying them onto the heap introduces interesting memory management issues.

阻止对包含对象的方法进行调用隐式地提升了 self 的引用计数。假设你有一个设置器为您的类的名称属性,如果您在一个内部调用 name = @foo块,编译器将其视为 [self setName:@foo] 并保留 self ,以便它赢得'在块仍在周围时被解除分配。

Blocks which make calls to methods on the containing object implicitly boost self's reference count. Suppose you have a setter for the name property of your class, if you call name = @"foo" inside a block, the compiler treats this as [self setName:@"foo"] and retains self so that it won't be deallocated while the block is still around.

实现EventEmitter意味着拥有长期的块。为了防止隐式的保留,发件人的用户需要在块之外创建一个 __块引用 self 例如:

Implementing an EventEmitter means having long-lived blocks. To prevent the implicit retain, the user of the emitter needs to create a __block reference to self outside of the block, ex:

__block *YourClass this = self;
[emitter on:@"eventName" callBlock:...
   [this setName:@"foo"];...
}];

这种方法唯一的问题是这个可能会在调用处理程序之前解除分配。所以用户必须在被释放时取消注册他们的听众。

The only problem with this approach is that this may be deallocated before the handler is invoked. So users must unregister their listeners when being deallocated.

有经验的Objective-C开发人员期待互动图书馆使用熟悉的图案。代表们是一个非常熟悉的模式,因此规范开发人员希望使用它。

Experienced Objective-C developers expect to interact with libraries using familiar patterns. Delegates are a tremendously familiar pattern, and so canonical developers expect to use it.

幸运的是,代理模式和基于块的侦听器不是互斥的。虽然我们的发射器必须能够处理来自许多地方的监听器(有一个委托不起作用),但是我们仍然可以公开一个接口,允许开发人员与发射器进行交互,就像他们的类是委托一样。

Fortunately, the delegate pattern and block-based listeners are not mutually exclusive. Although our emitter must be able to be handle listeners from many places (having a single delegate won't work) we could still expose an interface which would allow developers to interact with the emitter as though their class was the delegate.

我们尚未实施,但我们可能会根据用户的要求。

We haven't implemented this yet, but we probably will based on requests from users.

我不再工作,产生了这个问题,很高兴地回到了我的本土JavaScript。

I'm no longer working on the project that spawned this question, having quite happily returned to my native land of JavaScript.

接管这个项目的智能开发人员决定正确地退出我们的基于块的EventEmitter。
即将发布的版本已切换到 ReactiveCocoa

The smart developers who took over this project decided correctly to retire our custom block-based EventEmitter entirely. The upcoming release has switched to ReactiveCocoa.

这给我们比以前提供的EventEmitter库更高级别的信令模式,并允许它们比我们基于块的事件处理程序或类级别的方法更好地封装信号处理程序的状态。

This gives them a higher level signaling pattern than our EventEmitter library previously afforded, and allows them to encapsulate state inside of signal handlers better than our block-based event handlers or class-level methods did.

推荐答案

个人而言,我讨厌使用代理。因为C的结构是如何客观化的,所以它真的搞砸了代码如果我必须创建一个单独的对象/添加一个协议,只是为了被通知你的一个事件,我必须实现5/6。因此,我更喜欢块。

Personally, I hate using delegates. Because of how objective-C is structured, It really clutters code up If I have to create a separate object / add a protocol just to be notified of one of your events, and I have to implement 5/6. For this reason, I prefer blocks.

尽管他们(块)确实有其缺点(e.x.内存管理可能很棘手)。它们易于扩展,易于实现,并且在大多数情况下仅仅是有意义的。

While they (blocks) do have their disadvantages (e.x. memory management can be tricky). They are easily extendable, simple to implement, and just make sense in most situations.

尽管苹果的设计结构可能使用发送者 - 委托方法,这只是为了向后兼容。最近的Apple API一直在使用block(e.x. CoreData),因为它们是Objective-C的未来。虽然它们可以在使用过程中混乱代码,但它也允许更简单的匿名代理,这在目标C中是不可能的。

While apple's design structures may use the sender-delegate method, this is only for backwards compatibility. More recent Apple APIs have been using blocks (e.x. CoreData), because they are the future of objective-c. While they can clutter code when used overboard, it also allows for simpler 'anonymous delegates', which is not possible in objective C.

最后,它真的很由此可见:
您是否愿意放弃一些较旧的,更加日久的平台,以换取使用块与代表?代表的一个主要优点是:保证可以在任何版本的objc-runtime中运行,而块是该语言的最新补充。

In the end though, it really boils down to this: Are you willing to abandon some older, more dated platforms in exchange for using blocks vs. a delegate? One major advantage of a delegate is that it is guaranteed to work in any version of the objc-runtime, whereas blocks are a more recent addition to the language.

至于 NSNotificationCenter / KVO 是关心的,它们都是有用的,有其目的,但作为代表,它们并不意图被使用。也不能将结果发送给发件人,并且在某些情况下,这是至关重要的(例如, -webView:shouldLoadRequest:)。

As far as NSNotificationCenter/KVO is concerned, they are both useful, and have their purposes, but as a delegate, they are not intended to be used. Neither can send a result back to the sender, and for some situations, that is vital (-webView:shouldLoadRequest: for example).

这篇关于Objective-C库中回调的选择器或块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆