cocos2d-x 3.0 final 和cocos2d-x 3.2 均测试有效, 其他版本没试
在EventDispatcher::updateListener(Event* event)中, 找到如下代码并添加一句
if (event->geType() == Event::Type::TOUCH)
{
onUpdateListeners(EventListenerTouchOneByOne::LISTENER_ID)
onUpdateListeners(EventListenerTouchAllAtOnce::LISTENER_ID)
// 加这句, 参数就是常量cocos2d::FontAtlas::EVENT_PURGE_TEXTURES, 这只是一个临时的快速解决办法, 不符合整体设计思路
onUpdateListeners("__cc_FontAtlasPurgeTextures");
}
else
{
onUpdateListeners(__getListenerID(event))
}
原因:
label生成时会同时生成一个EventListenerCustom, 但是在删除Label对应的listener时, 这个listener没有被从全局listener vector里移除.
手动删除label时, 通常是某个事件回调里调用Node::removeFromParent
顺序如下, 如有不对请大家指出
1, 点击某个按钮或其它什么东西,
2, 进入EventDispatcher::dispatchEvent, 在这个函数里
(1) DispatchGuard guard(_inDispatch)被加了1, 直到gurad析构才-1
(2) 调用到点击的回调函数, 里面一般会有removeFromParent
(3) removeFromParent会导致调用Ref::release(), 这里引用减至0会delete this, 会导致调用各个父类的析构函数.
(4) Node::~Node()里_eventDispatcher->removeEventListenerForTarget(this)会去删除这个label的listener
(5) EventDispatcher::removeEventListenerForTarget里调用EventDispatcher::removeEVentListener
(6) EventDispatcher::removeEVentListener里的lamda函数removeListenerInVector里, CC_SAFE_RELEASE(l)这句前面有个判断_inDispatch==0始终为false, 前面第(2)步这个值已经被+1了. 于是label的listener只调用了CC_SAFE_RETAIN而没有调用CC_SAFE_RELEASE, refCount加了1. 同时该listener::setRegistered(false)
(7) EventDispatcher::dispatchEvent的最后一句, updateListeners(event)里, 会去删除刚才没删掉的listener
(8) EventDispatcher::updateListener里调用onUpdateListeners()就会去删除刚才没删掉的listener.
(9) 但是纵观全代码, 没有一处会抛出一个EventListenerCustom且eventName为cocos2d::FontAtlas::EVENT_PURGE_TEXTURES的Event, 所以label的listener没有机会得到清除, 当然也有可能是我没找到
(10) 为什么加的那一句在if里而不是else, 因为if的代码块只有touch事件触发, 而else是每一帧都会触发