From 111a2ef4dec81415da73754a988640df91d36bee Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 17 Sep 2013 16:59:54 +0800 Subject: [PATCH] issue #2087: [dispatcher] Fixing BugTest/Bug422 crashes. --- .../event_dispatcher/CCEventDispatcher.cpp | 156 +++++++++++++----- cocos2dx/event_dispatcher/CCEventDispatcher.h | 11 +- 2 files changed, 124 insertions(+), 43 deletions(-) diff --git a/cocos2dx/event_dispatcher/CCEventDispatcher.cpp b/cocos2dx/event_dispatcher/CCEventDispatcher.cpp index cb796bb0a7..c9b6f8718f 100644 --- a/cocos2dx/event_dispatcher/CCEventDispatcher.cpp +++ b/cocos2dx/event_dispatcher/CCEventDispatcher.cpp @@ -58,11 +58,17 @@ private: NS_CC_BEGIN +EventDispatcher::EventListenerItem::~EventListenerItem() +{ + CC_SAFE_RELEASE(this->node); +} + EventDispatcher::EventDispatcher() : _inDispatch(0) , _listeners(nullptr) , _isEnabled(true) { + _toAddedListeners.reserve(50); } EventDispatcher::~EventDispatcher() @@ -82,25 +88,33 @@ void EventDispatcher::addEventListenerWithItem(EventListenerItem* item) _listeners = new std::map*>(); } - std::vector* listenerList = nullptr; - - auto itr = _listeners->find(item->listener->type); - if (itr == _listeners->end()) + if (_inDispatch == 0) { - listenerList = new std::vector(); - listenerList->reserve(100); - _listeners->insert(std::make_pair(item->listener->type, listenerList)); + std::vector* listenerList = nullptr; + + auto itr = _listeners->find(item->listener->type); + if (itr == _listeners->end()) + { + listenerList = new std::vector(); + listenerList->reserve(100); + _listeners->insert(std::make_pair(item->listener->type, listenerList)); + } + else + { + listenerList = itr->second; + } + + listenerList->insert(listenerList->begin(), item); } else { - listenerList = itr->second; + _toAddedListeners.push_back(item); } - - listenerList->insert(listenerList->begin(), item); } void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node) { + CCASSERT(listener && node, "Invalid parameters."); CCASSERT(!listener->_isRegistered, "The listener has been registered."); if (!listener->checkAvaiable()) @@ -108,6 +122,7 @@ void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* list auto item = new EventListenerItem(); item->node = node; + item->node->retain(); item->fixedPriority = 0; item->listener = listener; item->listener->retain(); @@ -120,6 +135,7 @@ void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* list void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority) { + CCASSERT(listener, "Invalid parameters."); CCASSERT(!listener->_isRegistered, "The listener has been registered."); CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority."); @@ -141,6 +157,8 @@ void EventDispatcher::removeEventListener(EventListener* listener) if (_listeners == nullptr || listener == nullptr) return; + bool isFound = false; + for (auto iter = _listeners->begin(); iter != _listeners->end();) { for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter) @@ -158,6 +176,7 @@ void EventDispatcher::removeEventListener(EventListener* listener) (*itemIter)->listener = nullptr; } + isFound = true; break; } } @@ -172,6 +191,9 @@ void EventDispatcher::removeEventListener(EventListener* listener) { ++iter; } + + if (isFound) + break; } if (_listeners->empty()) @@ -193,6 +215,9 @@ void EventDispatcher::setPriorityWithSceneGraph(EventListener* listener, Node* n if (item->listener == listener) { item->fixedPriority = 0; + + CC_SAFE_RETAIN(node); + CC_SAFE_RELEASE(item->node); item->node = node; return; } @@ -216,7 +241,7 @@ void EventDispatcher::setPriorityWithFixedValue(EventListener* listener, int fix if (item->node != nullptr) { item->node->dissociateEventListener(listener); - item->node = nullptr; + CC_SAFE_RELEASE_NULL(item->node); } return; } @@ -259,7 +284,7 @@ void EventDispatcher::dispatchEvent(Event* event, bool toSortListeners) } } - removeUnregisteredListeners(); + updateListenerItems(); } void EventDispatcher::dispatchTouchEvent(TouchEvent* event) @@ -331,7 +356,7 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) if (touchEventListener->onTouchBegan) { isClaimed = touchEventListener->onTouchBegan(*touchesIter, event); - if (isClaimed) + if (isClaimed && item->listener) { touchEventListener->_claimedTouches.push_back(*touchesIter); } @@ -355,14 +380,20 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) { touchEventListener->onTouchEnded(*touchesIter, event); } - touchEventListener->_claimedTouches.erase(removedIter); + if (item->listener) + { + touchEventListener->_claimedTouches.erase(removedIter); + } break; case TouchEvent::EventCode::CANCELLED: if (touchEventListener->onTouchCancelled) { touchEventListener->onTouchCancelled(*touchesIter, event); } - touchEventListener->_claimedTouches.erase(removedIter); + if (item->listener) + { + touchEventListener->_claimedTouches.erase(removedIter); + } break; default: CCASSERT(false, "The eventcode is invalid."); @@ -373,13 +404,13 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) // If the event was stopped, return directly. if (event->isStopped()) { - removeUnregisteredListeners(); + updateListenerItems(); return; } CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); - if (isClaimed && touchEventListener->_needSwallow) + if (isClaimed && item->listener && touchEventListener->_needSwallow) { if (isNeedsMutableSet) { @@ -444,16 +475,16 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) // If the event was stopped, return directly. if (event->isStopped()) { - removeUnregisteredListeners(); + updateListenerItems(); return; } } } - removeUnregisteredListeners(); + updateListenerItems(); } -void EventDispatcher::removeUnregisteredListeners() +void EventDispatcher::updateListenerItems() { if (!_listeners) return; @@ -461,17 +492,19 @@ void EventDispatcher::removeUnregisteredListeners() auto listenerItemIter = _listeners->begin(); while (listenerItemIter != _listeners->end()) { - auto removeIterBegin = std::remove_if(listenerItemIter->second->begin(), listenerItemIter->second->end(), [](const EventListenerItem* item){ - return item->listener == nullptr; - }); - - for (auto iter = removeIterBegin; iter != listenerItemIter->second->end(); ++iter) + for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end();) { - delete (*iter); + if ((*iter)->listener == nullptr) + { + delete (*iter); + iter = listenerItemIter->second->erase(iter); + } + else + { + ++iter; + } } - listenerItemIter->second->erase(removeIterBegin, listenerItemIter->second->end()); - if (listenerItemIter->second->empty()) { delete listenerItemIter->second; @@ -483,6 +516,29 @@ void EventDispatcher::removeUnregisteredListeners() } } + if (!_toAddedListeners.empty()) + { + std::vector* listenerList = nullptr; + + for (auto& item : _toAddedListeners) + { + auto itr = _listeners->find(item->listener->type); + if (itr == _listeners->end()) + { + listenerList = new std::vector(); + listenerList->reserve(100); + _listeners->insert(std::make_pair(item->listener->type, listenerList)); + } + else + { + listenerList = itr->second; + } + + listenerList->push_back(item); + } + _toAddedListeners.clear(); + } + if (_listeners->empty()) { delete _listeners; @@ -563,14 +619,22 @@ void EventDispatcher::removeListenersForEventType(const std::string& eventType) for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) { (*iter)->listener->release(); - delete (*iter); + if (_inDispatch) + { + (*iter)->listener = nullptr; + } + else + { + delete (*iter); + } } - listenerItemIter->second->clear(); - - delete listenerItemIter->second; - - _listeners->erase(listenerItemIter); + if (!_inDispatch) + { + listenerItemIter->second->clear(); + delete listenerItemIter->second; + _listeners->erase(listenerItemIter); + } } } @@ -584,16 +648,28 @@ void EventDispatcher::removeAllListeners() for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) { (*iter)->listener->release(); - delete (*iter); + if (_inDispatch) + { + (*iter)->listener = nullptr; + } + else + { + delete (*iter); + } } - listenerItemIter->second->clear(); - - delete listenerItemIter->second; + if (!_inDispatch) + { + listenerItemIter->second->clear(); + delete listenerItemIter->second; + } } - delete _listeners; - _listeners = nullptr; + if (!_inDispatch) + { + delete _listeners; + _listeners = nullptr; + } } void EventDispatcher::setEnabled(bool isEnabled) diff --git a/cocos2dx/event_dispatcher/CCEventDispatcher.h b/cocos2dx/event_dispatcher/CCEventDispatcher.h index 621262272b..51aff99973 100644 --- a/cocos2dx/event_dispatcher/CCEventDispatcher.h +++ b/cocos2dx/event_dispatcher/CCEventDispatcher.h @@ -110,6 +110,7 @@ private: int fixedPriority; // The higher the number, the higher the priority Node* node; // Weak reference. EventListener* listener; + ~EventListenerItem(); }; /** Constructor of EventDispatcher */ @@ -127,15 +128,19 @@ private: /** Sorts the listeners of specified type by priority */ void sortAllEventListenerItemsForType(const std::string& eventType); - /** Removes all listeners that have been unregistered. */ - void removeUnregisteredListeners(); + /** Updates all listener items + * 1) Removes all listener items that have been marked as 'removed' when dispatching event. + * 2) Adds all listener items that have been marked as 'added' when dispatching event. + */ + void updateListenerItems(); private: /** * Listeners map. */ std::map*>* _listeners; - + std::vector _toAddedListeners; + int _inDispatch; bool _isEnabled; };