type
status
date
slug
summary
tags
category
icon
当正在分发事件的时候(_inDispath > 0),添加和删除监听器事件
EventDispatcher
中有表示当前分发的事件数的私有成员变量 _inDispatch
,它是一个 int
类型的数据,用于表示当前正有多少事件正在分发。既然是表示事件正在分发的数量,可定有 ++, -- 的操作,在DispatchEvent
中会有+1和-1的操作,但是藏得比较深,怎么个深法,看下述源码。我去,这啥都都没有啊???发现这里面只有使用
_inDispatch
创建了一个变量,并没有++,- -操作。其实 DispatchGuard
这个类的构造函数的参数是一个 int
类型的引用,构造时候对其+1,析构函数的时候会-1操作。用法很妙,借助了局部变量是在栈里面这个特性,当方法DispatchEvent
结束的时候,局部变量guard会析构,此时会-1操作。下面是 DispatchGuard
的源码。<!-- more -->
了解了
_inDispatch
的意义,我们来看看添加事件监听器和删除事件监听器的时候,如果正在分发事件(_inDispatch > 0
)会怎么处理。上述代码是监听器添加的时候的代码,可以看到如果当时正在分发事件,会把当前需要添加的监听器添加到待添加向量(
_toAddedListeners
)中,那么也就是说在事件分发完毕之后监听器需要从toAddedListeners
中转移到正式向量中,这部分代码可以在updateListeners
中看到,此方法会在事件分发结束之后调用。代码中,除了添加事件监听器有个待加入向量外,删除事件监听器也有一个待删除向量(不过这个好像是废话),开头有判断当前是否还是处于事件分发中。
Cocos Bug 之 DirtyFlag
上面的代码中,我删了一些代码,因为代码太多影响阅读。其中就有很多涉及到了Dirty Flag,望文取义的话是脏标记,问题是这个脏是什么脏?
下面来看一下添加监听器和移除监听器的代码部分。
代码中可以看到,这个 DirtyFlag 是设置给
ListenerID
的,每当新添加一个 Listener
,或则删除一个 Listener
的时候,就会给当前 Listener
的 ListenerID
添加一个 DirtyFlag。说明这个脏是指 ListenerID
对应的监听器向量列表需要重新排序了,如果不脏就不需要排序。那么问题来了:
照理只要出现了删除,修改,添加监听器的时候,监听器列表需要重新排序,都需要设置相应的 DirtyFlag 操作。但是 Cocos-2dx v3.10 里面的
updateListeners
函数有删除监听器的操作,然而并没有设置相应的 DirtyFlag 操作。此问题我在 Cocos2dx github 的 issues中有回答问题链接这个就是一个 Bug 了,放着不管会抛出以下异常
代码中的
Gt0Index()
方法其实就是获取到当前监听器里诶包中 fixedPriority == 0 的监听器在监听器向量中的位置,它只有在给 Listener
排序的时候会设置,但是如果更新了对应 ListenerID
的向量(EventListenerVector
),但是没有重新排序,就会出现 _gt0Index
未及时更新的情况,导致抛出这个异常。
排序的时候,会判断排序的这个 ListenerID
是否处于Dirty
的状态,只有脏状态才会排序,这算优化吧,所以必须在 updateListener
的时候加上 DirtyFlag。
Bug 修复PS: 场景切换的时候 EventDispatcher 会设置成 _isEnabled = false; 这时候分发自定义事件是无效的。
- Author:NotionNext
- URL:https://tangly1024.com/article/example-7
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts