考虑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))
仅出现在重载集中。
那么,完成同一件事的快捷方式是什么?
答案 0 :(得分:2)
您可以使用的一个技巧是重新组织代码。无需在addObserver
内创建多个(通用)NotificationCenter
方法,而是将它们移到您的通知类型(“基本和自定义通知”)中并使用协议对其进行形式化。然后,您可以使用单个函数扩展此协议,以添加addOnce
逻辑。当您的基本通知和自定义通知实施此协议时,它们会自动继承此新的addOnce
功能,而无需任何重复的代码。
以下是如何实现该想法的示例:
首先创建一个新协议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