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 的时候,就会给当前 ListenerListenerID 添加一个 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; 这时候分发自定义事件是无效的。
Cocos多模块热更新方案Cocos内存管理源码解析
Loading...