作为练习,我正在实现NSNotificationCenter。我最初用于保存观察者的Map的数据结构是:
protocol CustomObserver : Hashable {
func receiveNotification(userInfo: [AnyHashable : Any]?)
}
//....class declaration and init for CustomNotificationCenter
private var notificationsMap: [String: Set<CustomObservers>] = [:]
其中CustomObservers将有一个receiveNotification(...)调用。然而,我发现我不能在Swift中拥有一个协议集:
// This syntax did not work given the above code blocks.
Set<CustomObserver>
在大量的堆栈溢出之后,我找不到一个优雅的解决方案。所有的解决方案似乎都涉及:
1.制定观察员协议。
1.创建一个符合观察者协议的类。
1.使所有观察者都成为上述类的子类。
如果任何人有一个不涉及创建新类的Set的优雅解决方案,我洗耳恭听。在此之前...
我决定尝试使用这个数据结构:
private var notificationsMap: [String: [AnyHashable: Selector]] = [:]
这样我就不用依赖协议来定义receiveNotification行为,而是用一个选择器来调用订阅通知的每个对象。
在NotificationCenter的post函数中,我有这样的代码:
1.查找与通知名称关联的字典。
1.遍历字典,在每个对象上调用选择器。
func post(name: String, object: Any?, userInfo: [AnyHashable : Any]?) {
if let obsArray = notificationsMap[name] {
for (object, selector) in obsArray {
object.performSelector(onMainThread: selector, withObject: nil, waitUntilDone: true)
}
}
}
但是,在performSelector行中,我得到了以下错误:
Value of type 'AnyHashable' has no member 'performSelector'
那么我该怎么做呢?我该怎么执行Selector?或者...我该怎么让Set工作呢?
1条答案
按热度按时间q3aa05251#
我不知道你是否会称之为“优雅的解决方案”,但我会使用类型擦除,这与AnyCollection或AnyPublisher中使用的原理相同:
现在可以实现
notificationsMap
属性了备注
为了简单起见,我添加了一个UUID来满足
Equatable
和Hashable
的要求,但在CustomObserver
中使用标识符或名称可能更好。