仅当可以调用另一种方法时,如何使该方法出现在“过载集”中?

时间:2018-07-05 15:21:36

标签: swift

考虑NotificationCenter上的扩展,该扩展对符合某些协议的通知对象进行特殊处理(是的,这可能更常见,但这是一个示例,可以帮助演示我的真实问题)。

extension NotificationCenter {

  func addObserver<Note: BasicNotification>(using block: @escaping (Note) -> ())
  -> NotificationToken {
    let observer = addObserver(forName: Note.notificationName, object: nil,
        queue: nil, using: { note in
      block(Note(notification: note))
    })
    return NotificationToken(observer: observer, center: self)
  }

  func addObserver<Note: CustomNotification>(using block: @escaping (Note) -> ())
  -> NotificationToken {
    let observer = addObserver(forName: Note.notificationName, object: nil,
        queue: nil, using: { note in
      block(note.object as! Note)
    })
    return NotificationToken(observer: observer, center: self)
  }

}

现在,考虑何时我们希望此通知仅触发一次,然后注销......

extension NotificationCenter {

  func observeOnce<Note: BasicNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

  func observeOnce<Note: CustomNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

}

这是完全相同的代码。我真正想要的是一种observeOnce方法-我不想写其中两个。

如果我不使用任何条件一致性...

  func observeOnce<Note>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

我收到一个错误的Cannot invoke 'addObserver' with an argument list of type '(using: (Note) -> ())',这很合理。

如果我使用通用的基本协议(都符合)...

  func observeOnce<Note: SomeNotification>(using block: @escaping (Note) -> ()) {
    var token: NotificationToken!
    token = addObserver(using: { (note: Note) in
      block(note)
      token.reset()
    })
  }

我得到了完全相同的错误,但意义不大-我希望有关呼叫的内容有些模棱两可,而不是根本不存在。

在看到&表示符合多种协议的含义之后,我确实尝试在极不可能的情况下使用BasicNotification | CommonNotification,但这可能具有某些含义...但是,它当然行不通。 / p>

我也尝试了很多其他选择,但无济于事。我想做的是,如果有observeOnce个电话可供呼叫,则可以通话。

在C ++中,我会做类似的事情(不会通过编译器运行它-希望您能得到我想做的事情)...

template <typename T>
auto observeOnce(std::function<void (T)> block)
-> decltype(void(this->addObserver(std::move(block))))
{
  // do my stuff here
}

上面的代码基本上意味着,如果可以调用observeOnce,则函数addObserver(std::move(block))仅出现在重载集中。

那么,完成同一件事的快捷方式是什么?

1 个答案:

答案 0 :(得分:2)

您可以使用的一个技巧是重新组织代码。无需在addObserver内创建多个(通用)NotificationCenter方法,而是将它们移到您的通知类型(“基本和自定义通知”)中并使用协议对其进行形式化。然后,您可以使用单个函数扩展此协议,以添加addOnce逻辑。当您的基本通知和自定义通知实施此协议时,它们会自动继承此新的addOnce功能,而无需任何重复的代码。

Refactoring scheme

示例

以下是如何实现该想法的示例:

首先创建一个新协议ObservableNotification,该协议允许将观察者block添加到NotificationCenter

protocol ObservableNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken
}

然后,让您的Notification协议从此ObservableNotification协议继承

protocol NameableNotification {
    static var notificationName: NSNotification.Name {get}
}

protocol CustomNotification: NameableNotification, ObservableNotification {}
protocol BasicNotification: NameableNotification, ObservableNotification {
    init(notification: Notification)
}

使用协议扩展将addObserver方法(从NotificationCenter)移动到相应的协议作为默认实现:

extension BasicNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken {
        let observer = center.addObserver(forName: Self.notificationName, object: nil, queue: nil) { note in
            block(Self(notification: note))
        }
        return NotificationToken(observer: observer, center: center)
    }
}

extension CustomNotification {
    static func addObserver(to center: NotificationCenter, using block: @escaping (Self)->Void) -> NotificationToken {
        let observer = center.addObserver(forName: Self.notificationName, object: nil, queue: nil) { note in
            block(note.object as! Self)
        }
        return NotificationToken(observer: observer, center: center)
    }
}

这样,您可以使用ObservableNotification方法的默认实现扩展observeOnce协议,并能够在符合ObservableNotification({{1 }}和CustomNotification)。像这样:

BasicNotification