Idiomatic Swift多路复用通知?

时间:2015-02-13 16:12:46

标签: swift design-patterns notifications idiomatic generics

我正在定义一个类结构,需要在有趣的事情发生时通知其消费者(获取新数据,等等)。类似于委托关系,但可能有很多消费者。与将NSNotification投入风中的关系更为直接。

我对大多数Objective-C程序的倾向只是定义一个协议,让那些消费者实现它并将自己注册为id<MyProtocol>;我把它们填入NSMutableSet,我会在适当的时候迭代它。我花在编写C#上的时间会让我尝试修改这种方法,以便在Swift中使用泛型(la private var myConsumers = Set<MyProtocol>())。据我所知,事实证明这是一个黑暗而痛苦的兔子洞。但是,不要深入研究它,让我备份并尝试解决真正的问题。

所以:我有一些类,实例需要通知0-N消费者有趣的事情发生。允许这些消费者注册和取消注册是件好事,因为他们的生命周期可能比我的班级短。

实现这种模式的惯用Swift方法是什么?

3 个答案:

答案 0 :(得分:2)

Cocoa中多代理的惯用解决方案是通知,特别是使用addObserverForName(object:queue:usingBlock:)。通过你的关闭。保存返回值,并使用该返回值在将来取消注册。

有ObjC多播代表(Robbie Hanson's可能是我最喜欢的代理人之外的代表),但大部分时间它比它的价值更麻烦。通知是Cocoa管理非代表观察员的方式。

&#34;非代表&#34;这意味着&#34;被通知的东西,但从未被问过任何东西。&#34; &#34;多代表&#34;的问题这是一个无意义的术语。 A&#34;代表&#34;是你要求提供信息的东西;你所代表的东西&#34;决定的责任。观察员不是真的&#34;代表&#34; (虽然代表有时是观察员)。你什么都不问他们。他们无法控制决策。因此,多代表是无稽之谈。多个事情如何能够回答问题?为了使其更具体,委托使用非void方法。考虑拥有一个多代表&#34;意味着什么?为UITableViewDelegate。你怎么决定行高是多少?

如果您正在构建自己的,我可能会建议Dictionary<Key, ()->Void>其中&#34; key&#34;是您返回给调用者以便以后删除的句柄。这样你就不必担心关闭平等的疯狂(我同意Chris Lattner是一个非常开放的,可能无法解决的问题)。

答案 1 :(得分:0)

这是迄今为止我能够提出的最简单的事情,仿效MultiCastDelegate

struct MultiClosure<T, U> {
    private typealias Key = MultiClosureKey
    private let closures: [Key: T -> U]

    init() {closures = Dictionary<Key, T -> U>()}
    init(_ closure: T -> U) {closures = [Key(): closure]}

    private init(_ closures: [Key: T -> U]) {self.closures = closures}

    func run(t: T) {
        for closure in closures.values {closure(t)}
    }
}


private class MultiClosureKey: Hashable {
    // Is this ignorant? I don't know yet.
    // It seems to work so I haven't looked for a better solution.
    var hashValue : Int { return ObjectIdentifier(self).hashValue }
}

private func == (lhs: MultiClosureKey, rhs: MultiClosureKey) -> Bool {
    return lhs === rhs
}



func + <T, U>(left: MultiClosure<T, U>, right: MultiClosure<T, U>) -> MultiClosure<T, U> {
    return MultiClosure(left.closures + right.closures)
}

func += <T, U>(inout left: MultiClosure<T, U>, right: MultiClosure<T, U>) {
    left = left + right
}

func - <T, U>(left: MultiClosure<T, U>, right: MultiClosure<T, U>) -> MultiClosure<T, U> {
    return MultiClosure(left.closures - right.closures)
}

func -= <T, U>(inout left: MultiClosure<T, U>, right: MultiClosure<T, U>) {
    left = left - right
}

字典扩展:

func + <T, U>(var left: Dictionary<T, U>, right: Dictionary<T, U>) -> Dictionary<T, U> {
    for (key, value) in right {
        left[key] = value
    }
    return left
}

func += <T, U>(inout left: Dictionary<T, U>, right: Dictionary<T, U>) {
    left = left + right
}

func - <T, U>(var left: Dictionary<T, U>, right: Dictionary<T, U>) -> Dictionary<T, U> {
    for key in right.keys {
        left[key] = nil
    }
    return left
}

func -= <T, U>(inout left: Dictionary<T, U>, right: Dictionary<T, U>) {
    left = left - right
}

答案 2 :(得分:0)

我写了一个原生的Swift通知广播系统,它使开发人员能够使用switch-case语法匹配特定的通知类型,并对NSNotificationCenter起作用。

我现在处理的通知如下:

func handleNotification(notification: PrimitiveNotificationType) {  
    switch notification {
    case let aNotification as CustomNotification:
        let initialFrame = aNotification.initialFrame
        let finalFrame = aNotification.finalFrame
        print("Initial frame: \(initialFrame)")
        print("Final frame: \(finalFrame)")
    default: return
    }
}

以下是帖子:https://wezzard.com/2015/08/08/notification-handling-best-practice-in-swift/

以下是代码:https://github.com/WeZZard/Nest

另外,这些东西仅适用于Swift 2。