在Swift中,注册"anywhere"成为一个协议的委托人

In Swift, register "anywhere" to be a delegate of a protocol

我有一个复杂的观点class,

class Snap:UIViewController, UIScrollViewDelegate
   {
   }

最终结果是用户可以选择一种颜色...

protocol SnapProtocol:class
    {
    func colorPicked(i:Int)
    }
class Snap:UIViewController, UIScrollViewDelegate
   {
   someDelegate.colorPicked(blah)
   }

那么谁来处理呢。

假设您确定响应链上有一些东西,甚至遍历容器视图,这是一个SnapProtocol。如果是这样,您可以使用 来调用它

var r : UIResponder = self
repeat { r = r.nextResponder()! } while !(r is SnapProtocol)
(r as! SnapProtocol).colorPicked(x)

如果您愿意,可以使用这个最高级的扩展程序

public extension UIResponder        // walk up responder chain
    {
    public func next<T>() -> T?
        {
        guard let responder = self.nextResponder()
            else { return nil }
        return (responder as? T) ?? responder.next()
        }
    }

courtesy these guys 并安全地找到你上面的任何 SnapProtocol

 (next() as SnapProtocol?)?.colorPicked(x)

太好了。

但是。如果想要获得 colorPicked 的对象是一个远离你的骑士移动,沿着一些复杂的侧链,and/or 你甚至不知道哪个对象想要它。

我目前的解决方案是这样的,我有一个单例 "game manager" -like class,

public class .. a singleton
    {

    // anyone who wants a SnapProtocol:
    var useSnap:SnapProtocol! = nil

    }

有些变态class,哪里都想吃SnapProtocol ...

class Dinosaur:NSObject, SnapProtocol
    {
    ....
    func colorPicked(index: Int)
        {...}

...所以,要将其设置为所需的委托,请使用单例

 thatSingleton.useSnap = dinosaur

很明显,这很好用。

另请注意,我可以轻松地在单例中编写一个小系统,以便该协议的任意数量的用户都可以动态地 register/deregister 那里并接听电话。

但它有明显的问题,它不是很 "pattern" 并且看起来非常不合惯用语。

所以。我真的在 Swift 环境中以正确的方式这样做吗?

我真的把自己弄糊涂了吗,我应该在今天的 iOS 中使用一些完全不同的模式来发送这样的 "messages to anyone who wants them?" 。 .. 也许我什至不应该使用协议?

"Send out messages to anyone who wants them" 几乎就是 NSNotificationCenter 的描述。

没错,它不是从一开始就为 Swift 模式设计的 API,例如闭包、强类型和面向协议的编程。 (如其他 comments/answers 所述,如果您确实需要此类功能,开源 SwiftNotificationCenter 是一个不错的选择。)

然而,NSNotificationCenter 稳健且久经沙场 — 它是每次通过 运行循环。


这是在 Swift 中使用 NSNotificationCenter 的非常简洁的操作方法:

Swift标准中没有"protocol based"通知机制 库或运行时。可以在此处找到一个不错的实现 https://github.com/100mango/SwiftNotificationCenter。来自自述文件:

A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety.

  • Type Safe

    No more userInfo dictionary and Downcasting, just deliver the concrete type value to the observer.

  • Thread Safe

    You can register, notify, unregister in any thread without crash and data corruption.

  • Memory Safety

    SwiftNotificationCenter store the observer as a zeroing-weak reference. No crash and no need to unregister manually.

It's simple, safe, lightweight and easy to use for one-to-many communication.

使用 SwiftNotificationCenter,符合 class 的(a 的实例)可以像这样注册自己:

class MyObserver: SnapProtocol {
    func colorPicked(i: Int) {
        print("color picked:", i)
    }
    init() {
        NotificationCenter.register(SnapProtocol.self, observer: self)
    }
}

并且向所有符合要求的注册观察员广播通知 完成为

NotificationCenter.notify(SnapProtocol.self) {
    [=11=].colorPicked(x)
}