我正在使用Swift中的自定义消息调度程序。我想有调度员,可以:
Hashable
发送。以下是代码:
import Foundation
protocol EventDispatcherProtocol: class {
typealias T: Hashable
func dispatcherDidDispatchEvent(event: T)
}
class EventListenerWrapper<T: EventDispatcherProtocol> {
weak var object: T?
init(_ object: T) {
self.object = object
}
}
class EventDispatcher<KeyType: Hashable, U: EventDispatcherProtocol> {
private var objects = Dictionary<KeyType, [EventListenerWrapper<U>]>()
func add(#listener: U, forEvent event: KeyType) {
let wrapper = EventListenerWrapper(object: listener)
// get all wrappers
if let storedWrappers = objects[event] {
// check if there is such objects already wrapped for this type of event
var found = false
for storedWrapper in storedWrappers {
if let storedObject = storedWrapper.object
where (storedObject as! AnyObject) === (wrapper.object as! AnyObject) {
// Found it!
found = true
break
}
}
if found == false {
// If not found then add the wrapper for this event
var updatedWrappers = storedWrappers
updatedWrappers.append(wrapper)
self.objects[event] = updatedWrappers
}
} else {
self.objects[event] = [wrapper]
}
}
func dispatch(event: KeyType) {
// Enumerate through wrappers
if let storedWrappers = objects[event] {
var idxToRemove = [Int]()
var currentIdx = 0
for storedWrapper in storedWrappers {
// if there is object to dispatch - dispatch message
// otherwise add index of this object to remove wrapper later
if let storedObject = storedWrapper.object {
// storedObject.dispatcherDidDispatchEvent(event) /// <- cannot invoke 'this method' with an argument list of type '(KeyType)'
} else {
idxToRemove.append(currentIdx)
}
currentIdx++
}
// enumerate through reversed array of indexes to remove
// and remove items, update wrappers at the end.
idxToRemove = idxToRemove.reverse()
var updatedWrappers = storedWrappers
for idx in idxToRemove {
updatedWrappers.removeAtIndex(idx)
}
objects[event] = updatedWrappers
}
}
}
// EXAMPLE
enum CustomEvent {
case Start, Stop
}
class CustomListener: EventDispatcherProtocol {
func dispatcherDidDispatchEvent(event: CustomEvent) {
println("CustomListener heard that event! \(event)")
}
}
// Create listeners and wrap them
var listener1 = CustomListener()
var listener2 = CustomListener()
// Create dispatcher
var dispatcher = EventDispatcher<CustomEvent, CustomListener>()
dispatcher.add(listener: listener1, forEvent: CustomEvent.Start)
dispatcher.add(listener: listener2, forEvent: CustomEvent.Stop)
dispatcher.dispatch(CustomEvent.Start)
dispatcher.dispatch(CustomEvent.Stop)
不幸的是object.dispatcherDidDispatchEvent(event)
来电时出错了。我无法理解这有什么问题。它看起来对我来说正确。
提前谢谢!
编辑 - @Tobol建议后的工作解决方案
import Foundation
protocol EventDispatcherProtocol {
typealias T: Hashable
func dispatcherDidDispatchEvent(event: T)
}
class EventListenerWrapper<T: EventDispatcherProtocol> {
var object: T?
init(_ object: T) {
self.object = object
}
}
class EventDispatcher<U: EventDispatcherProtocol> {
typealias KeyType = U.T
private var objects = Dictionary<KeyType, [EventListenerWrapper<U>]>()
func add(#listener: U, forEvent event: KeyType) {
let wrapper = EventListenerWrapper(listener)
// get all wrappers
if let storedWrappers = objects[event] {
// check if there is such objects already wrapped for this type of event
// and if not found add the wrapper for this event
if storedWrappers.filter({($0.object as? AnyObject) === (listener as! AnyObject) }).count == 0 {
objects[event] = storedWrappers + [wrapper]
}
} else {
objects[event] = [wrapper]
}
}
func dispatch(event: KeyType) {
// Enumerate through wrappers
if var storedWrappers = objects[event] {
// Enumerate through stored wrappers and get indexes of objects to remove
var indexesToRemove = [Int]()
var currentIndex = 0
storedWrappers.filter({
var match = $0.object == nil
if match { indexesToRemove.append(currentIndex) }
currentIndex++
return match
})
// Reverse array of indexes to make removing process easier
for index in indexesToRemove.reverse() {
storedWrappers.removeAtIndex(index)
}
// Dispatch message on existing objects
for wrapper in storedWrappers {
wrapper.object!.dispatcherDidDispatchEvent(event)
}
objects[event] = storedWrappers
}
}
}
// EXAMPLE
enum CustomEvent {
case Start, Stop
}
class CustomListener: EventDispatcherProtocol {
func dispatcherDidDispatchEvent(event: CustomEvent) {
println("CustomListener heard that event! \(event)")
}
}
// Create listeners and wrap them
var listener1 = CustomListener()
// Create dispatcher
var dispatcher = EventDispatcher<CustomListener>()
dispatcher.add(listener: listener1, forEvent: CustomEvent.Start)
dispatcher.dispatch(CustomEvent.Start)
答案 0 :(得分:1)
storedObject.dispatcherDidDispatchEvent(event) /// <- cannot invoke 'this method' with an argument list of type '(KeyType)'
event
此处的类型为KeyType
,这是受Hashable
约束的通用类型。
dispatcherDidDispatchEvent()
采用CustomEvent
类型的参数。这不等于&#34; EventDispatcher
专用的可混合类型。&#34;
其中一个需要改变。
答案 1 :(得分:1)
我认为针对您的案例的最佳解决方案是将类声明更改为:
class EventDispatcher<U: EventDispatcherProtocol> {
typealias KeyType = U.T
它还将通过跳过冗余类型声明来简化EventDispatcher的创建:
var dispatcher = EventDispatcher<CustomListener<CustomEvent>>()
修改强> 由于在编写答案时代码被多次更改,因此我附上整个解决方案代码示例:
import Foundation
protocol EventDispatcherProtocol {
typealias T: Hashable
func dispatcherDidDispatchEvent(event: T)
}
class EventListenerWrapper<T: EventDispatcherProtocol> {
var object: T?
init(object: T) {
self.object = object
}
}
class EventDispatcher<U: EventDispatcherProtocol> {
typealias KeyType = U.T
private var objects = Dictionary<KeyType, [EventListenerWrapper<U>]>()
func add(#listener: U, forEvent event: KeyType) {
let wrapper = EventListenerWrapper(object: listener)
// get all wrappers
if let storedWrappers = objects[event] {
// check if there is such objects already wrapped for this type of event
var found = false
for storedWrapper in storedWrappers {
if let storedObject = storedWrapper.object
where (storedObject as! AnyObject) === (wrapper.object as! AnyObject) {
// Found it!
found = true
break
}
}
if found == false {
// If not found then add the wrapper for this event
var updatedWrappers = storedWrappers
updatedWrappers.append(wrapper)
self.objects[event] = updatedWrappers
}
} else {
self.objects[event] = [wrapper]
}
}
func dispatch(event: KeyType) {
// Enumerate through wrappers
if let storedWrappers = objects[event] {
var idxToRemove = [Int]()
var currentIdx = 0
for storedWrapper in storedWrappers {
// if there is object to dispatch - dispatch message
// otherwise add index of this object to remove wrapper later
if let storedObject = storedWrapper.object {
storedObject.dispatcherDidDispatchEvent(event) /// <- cannot invoke 'this method' with an argument list of type '(KeyType)'
} else {
idxToRemove.append(currentIdx)
}
currentIdx++
}
// enumerate through reversed array of indexes to remove
// and remove items, update wrappers at the end.
idxToRemove = idxToRemove.reverse()
var updatedWrappers = storedWrappers
for idx in idxToRemove {
updatedWrappers.removeAtIndex(idx)
}
objects[event] = updatedWrappers
}
}
}
// EXAMPLE
enum CustomEvent {
case Start, Stop
}
class CustomListener<T: Hashable>: EventDispatcherProtocol {
func dispatcherDidDispatchEvent(event: T) {
println("CustomListener heard that event! \(event)")
}
}
// Create listeners and wrap them
var listener1 = CustomListener<CustomEvent>()
var listener2 = CustomListener<CustomEvent>()
// Create dispatcher
var dispatcher = EventDispatcher<CustomListener<CustomEvent>>()
dispatcher.add(listener: listener1, forEvent: CustomEvent.Start)
dispatcher.add(listener: listener2, forEvent: CustomEvent.Stop)
dispatcher.dispatch(CustomEvent.Start)
dispatcher.dispatch(CustomEvent.Stop)