From 06bc92ff19b38855f907992213c5cb5b897cde54 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 12 Sep 2013 20:45:35 +0800 Subject: [PATCH] [dispatcher] Removing unused listeners after dispatching event. --- cocos2dx/event_dispatcher/CCEvent.cpp | 1 - .../event_dispatcher/CCEventDispatcher.cpp | 134 +++++++++++++++--- cocos2dx/event_dispatcher/CCEventDispatcher.h | 50 ++++--- 3 files changed, 140 insertions(+), 45 deletions(-) diff --git a/cocos2dx/event_dispatcher/CCEvent.cpp b/cocos2dx/event_dispatcher/CCEvent.cpp index 0711272757..0d952426d8 100644 --- a/cocos2dx/event_dispatcher/CCEvent.cpp +++ b/cocos2dx/event_dispatcher/CCEvent.cpp @@ -29,7 +29,6 @@ NS_CC_BEGIN Event::Event(const std::string& type) : _type(type) , _isStopped(false) -, _isValid(true) { } diff --git a/cocos2dx/event_dispatcher/CCEventDispatcher.cpp b/cocos2dx/event_dispatcher/CCEventDispatcher.cpp index 1979626e1e..4563114694 100644 --- a/cocos2dx/event_dispatcher/CCEventDispatcher.cpp +++ b/cocos2dx/event_dispatcher/CCEventDispatcher.cpp @@ -239,34 +239,20 @@ void EventDispatcher::dispatchEvent(Event* event) (*listenerIter)->listener->onEvent(event); - if ((*listenerIter)->id == 0) - { - delete (*listenerIter); - listenerList->remove(*listenerIter); - } - if (event->isStopped()) break; } - - if (listenerList->empty()) - { - _listeners->erase(iter); - CC_SAFE_DELETE(listenerList); - } - } - - if (_listeners->empty()) - { - CC_SAFE_DELETE(_listeners); } } - + + removeUnregisteredListeners(); } void EventDispatcher::dispatchTouchEvent(TouchEvent* event) { auto touchListeners = getListeners(TouchEvent::EVENT_TYPE); + if (touchListeners == nullptr) + return; std::vector oneByOnelisteners; oneByOnelisteners.reserve(touchListeners->size()); @@ -313,6 +299,10 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) auto oneByOneIter = oneByOnelisteners.begin(); for (; oneByOneIter != oneByOnelisteners.end(); ++oneByOneIter) { + // Skip if the listener was removed. + if ((*oneByOneIter)->id == 0) + continue; + bool isClaimed = false; std::vector::iterator removedIter; @@ -363,6 +353,12 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) } } + // If the event was stopped, return directly. + if (event->isStopped()) + { + removeUnregisteredListeners(); + return; + } CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); @@ -425,12 +421,61 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event) CCASSERT(false, "The eventcode is invalid."); break; } + + // If the event was stopped, return directly. + if (event->isStopped()) + { + removeUnregisteredListeners(); + return; + } } } + + removeUnregisteredListeners(); +} + +void EventDispatcher::removeUnregisteredListeners() +{ + if (!_listeners) + return; + + auto listenerItemIter = _listeners->begin(); + while ( listenerItemIter != _listeners->end()) + { + auto removeIterBegin = std::remove_if(listenerItemIter->second->begin(), listenerItemIter->second->end(), [](const EventListenerItem* item){ + return item->id == 0; + }); + + for (auto iter = removeIterBegin; iter != listenerItemIter->second->end(); ++iter) + { + delete (*iter); + } + + listenerItemIter->second->erase(removeIterBegin, listenerItemIter->second->end()); + + if (listenerItemIter->second->empty()) + { + delete listenerItemIter->second; + listenerItemIter = _listeners->erase(listenerItemIter); + } + else + { + ++listenerItemIter; + } + } + + if (_listeners->empty()) + { + delete _listeners; + _listeners = nullptr; + } } void EventDispatcher::sortAllEventListenerItems() { + if (_listeners == nullptr) + return; + for (auto listenerItemIter = _listeners->begin(); listenerItemIter != _listeners->end(); ++listenerItemIter) { // After sort: priority < 0, = 0, scene graph, > 0 @@ -464,13 +509,58 @@ void EventDispatcher::sortAllEventListenerItems() std::list* EventDispatcher::getListeners(const std::string& eventType) { - auto iter = _listeners->find(eventType); - if (iter != _listeners->end()) + if (_listeners != nullptr) { - return iter->second; + auto iter = _listeners->find(eventType); + if (iter != _listeners->end()) + { + return iter->second; + } } - + return nullptr; } +void EventDispatcher::removeListenersForEventType(const std::string& eventType) +{ + if (_listeners == nullptr) + return; + + auto listenerItemIter = _listeners->find(eventType); + if (listenerItemIter != _listeners->end()) + { + for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) + { + delete (*iter); + } + + listenerItemIter->second->clear(); + + delete listenerItemIter->second; + + _listeners->erase(listenerItemIter); + } +} + +void EventDispatcher::removeAllListeners() +{ + if (_listeners == nullptr) + return; + + for (auto listenerItemIter = _listeners->begin(); listenerItemIter != _listeners->end(); ++listenerItemIter) + { + for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) + { + delete (*iter); + } + + listenerItemIter->second->clear(); + + delete listenerItemIter->second; + } + + delete _listeners; + _listeners = nullptr; +} + NS_CC_END diff --git a/cocos2dx/event_dispatcher/CCEventDispatcher.h b/cocos2dx/event_dispatcher/CCEventDispatcher.h index 1a693c7859..cb1221908f 100644 --- a/cocos2dx/event_dispatcher/CCEventDispatcher.h +++ b/cocos2dx/event_dispatcher/CCEventDispatcher.h @@ -51,14 +51,6 @@ dispatched. class EventDispatcher { public: - struct EventListenerItem - { - int id; - Node* node; // Weak reference. - int fixedPriority; // The higher the number, the higher the priority - std::shared_ptr listener; - }; - /** Gets the singleton of EventDispatcher */ static EventDispatcher* getInstance(); @@ -72,7 +64,6 @@ public: */ int registerEventListenerWithFixedPriority(std::shared_ptr listener, int fixedPriority); - /** Unregisters a callback function by the unique ID. */ void unregisterEventListener(int listenerId); @@ -93,27 +84,42 @@ public: * event dispatcher list. */ void dispatchEvent(Event* event); - - /** Gets event listener list by event type. */ - std::list* getListeners(const std::string& eventType); - -private: - /** Constructor of EventDispatcher */ - EventDispatcher(); - - void registerEventListenerWithItem(EventListenerItem* item); - - /** Touch event needs to be processed different with other events since it needs support ALL_AT_ONCE and ONE_BY_NONE mode. */ - void dispatchTouchEvent(TouchEvent* event); + + /** Removes listeners by event type */ + void removeListenersForEventType(const std::string& eventType); + + /** Removes all listeners */ + void removeAllListeners(); public: /** Destructor of EventDispatcher */ ~EventDispatcher(); private: - + struct EventListenerItem + { + int id; + Node* node; // Weak reference. + int fixedPriority; // The higher the number, the higher the priority + std::shared_ptr listener; + }; + + /** Constructor of EventDispatcher */ + EventDispatcher(); + + void registerEventListenerWithItem(EventListenerItem* item); + + /** Touch event needs to be processed different with other events since it needs support ALL_AT_ONCE and ONE_BY_NONE mode. */ + void dispatchTouchEvent(TouchEvent* event); + + /** Gets event listener list by event type. */ + std::list* getListeners(const std::string& eventType); + /** Sorts all listeners by priority */ void sortAllEventListenerItems(); + + /** Remove listeners that have been unregistered. */ + void removeUnregisteredListeners(); private: /**