local b = class()
function B:on_money_change(money)
print(money,"B recive event")
end
EventSystem:on(Event.MoneyChanged,B.on_money_change,{target = B})
--定义回调函数和注册事件
local c = class()
function C:on_money_change(money)
print(money,"C recive event")
end
EventSystem:on(Event.MoneyChanged,C.on_money_change,{target = C})
EventSystem:emit(Event.MoneyChanged,10)
关键点:
- 在事件派发的过程中订阅该事件,订阅还有优先级,需要小心处理排序问题
- 在事件派发的过程中取消订阅该事件,需要采用标记移除,不能直接移除
- 在事件派发的过程中又派发了该事件,如何确定事件派发完成
--注册接口实现
function EventSystem:on( event, func, params )
--- ...
local event_listener = self._listeners[event]
params = params or {}
local priority = params.priority or 0 --事件优先级设定
local target = params.target
--- ...
local cb = {target = target, func = func, id = id, priority = priority}
table.insert(event_listener.list, cb)
id = id + 1
if priority > 0 then
event_listener.need_sort = true
self:sort(event_listener)
end
end
--排序事件
function EventSystem:sort( listener )
if listener.need_sort == true and listener.emit_count == 0 then
-- listener.emit_count == 0 当前事件没有处于派发状态
--[[事件处于派发状态时不能进行优先级排序原因是可能会造成回调的重复触发。
比如当前事件有4个回调 a, b, c, d,派发事件是顺序执行回调,当执行到第3个回调c时,如果在c回调中 又注册了一个优先级最高的回调e,立刻排序的话,e插入到第一位,c会被挤到第4位,顺序执行到第4个回调时,导致c又被调用一次
]]
table.sort(listener.list, function ( a, b )
if a.priority == b.priority then
return a.id < b.id
else
return a.priority > b.priority
end
end)
listener.need_sort = false;
end
end
--监听取消函数
function EventSystem:off( event, func, params )
--- ...
local event_listener = self._listeners[event]
params = params or {}
for i,cb in ipairs(event_listener.list) do
if cb.func == func and cb.target == params.target then
if event_listener.emit_count > 0 then
-- 派发过程中只进行标记删除
cb.need_remove = true
event_listener.need_clean = true
else
table.remove(event_listener.list, i)
end
break;
end
end
end
--事件派发接口
function EventSystem:emit( event, ... )
--- ...
local event_listener = self._listeners[event]
local interrupt = false
local length = #event_listener.list
-- 这里不能使用ipairs,确保不会触发在派发过程中注册的事件
-- 只取当前已经注册的事件数量,如果在派发过程中再注册(调用了table.insert),本次派发也不会调用
for i = 1, length do
if interrupt == true then
break
end
local cb = event_listener.list[i]
if cb.func and cb.need_remove ~= true then
event_listener.emit_count = event_listener.emit_count + 1
if cb.target then
interrupt = cb.func(cb.target, ...)
else
interrupt = cb.func(...)
end
event_listener.emit_count = event_listener.emit_count - 1
end
end
self:sort(event_listener);
self:clean(event_listener);
return interrupt
end