issue #2087: [dispatcher] Fixing BugTest/Bug422 crashes.

This commit is contained in:
James Chen 2013-09-17 16:59:54 +08:00
parent 81d8558c3c
commit 111a2ef4de
2 changed files with 124 additions and 43 deletions

View File

@ -58,11 +58,17 @@ private:
NS_CC_BEGIN NS_CC_BEGIN
EventDispatcher::EventListenerItem::~EventListenerItem()
{
CC_SAFE_RELEASE(this->node);
}
EventDispatcher::EventDispatcher() EventDispatcher::EventDispatcher()
: _inDispatch(0) : _inDispatch(0)
, _listeners(nullptr) , _listeners(nullptr)
, _isEnabled(true) , _isEnabled(true)
{ {
_toAddedListeners.reserve(50);
} }
EventDispatcher::~EventDispatcher() EventDispatcher::~EventDispatcher()
@ -82,6 +88,8 @@ void EventDispatcher::addEventListenerWithItem(EventListenerItem* item)
_listeners = new std::map<std::string, std::vector<EventListenerItem*>*>(); _listeners = new std::map<std::string, std::vector<EventListenerItem*>*>();
} }
if (_inDispatch == 0)
{
std::vector<EventListenerItem*>* listenerList = nullptr; std::vector<EventListenerItem*>* listenerList = nullptr;
auto itr = _listeners->find(item->listener->type); auto itr = _listeners->find(item->listener->type);
@ -98,9 +106,15 @@ void EventDispatcher::addEventListenerWithItem(EventListenerItem* item)
listenerList->insert(listenerList->begin(), item); listenerList->insert(listenerList->begin(), item);
} }
else
{
_toAddedListeners.push_back(item);
}
}
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node) void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{ {
CCASSERT(listener && node, "Invalid parameters.");
CCASSERT(!listener->_isRegistered, "The listener has been registered."); CCASSERT(!listener->_isRegistered, "The listener has been registered.");
if (!listener->checkAvaiable()) if (!listener->checkAvaiable())
@ -108,6 +122,7 @@ void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* list
auto item = new EventListenerItem(); auto item = new EventListenerItem();
item->node = node; item->node = node;
item->node->retain();
item->fixedPriority = 0; item->fixedPriority = 0;
item->listener = listener; item->listener = listener;
item->listener->retain(); item->listener->retain();
@ -120,6 +135,7 @@ void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* list
void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority) void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{ {
CCASSERT(listener, "Invalid parameters.");
CCASSERT(!listener->_isRegistered, "The listener has been registered."); 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."); 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) if (_listeners == nullptr || listener == nullptr)
return; return;
bool isFound = false;
for (auto iter = _listeners->begin(); iter != _listeners->end();) for (auto iter = _listeners->begin(); iter != _listeners->end();)
{ {
for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter) for (auto itemIter = iter->second->begin(); itemIter != iter->second->end(); ++itemIter)
@ -158,6 +176,7 @@ void EventDispatcher::removeEventListener(EventListener* listener)
(*itemIter)->listener = nullptr; (*itemIter)->listener = nullptr;
} }
isFound = true;
break; break;
} }
} }
@ -172,6 +191,9 @@ void EventDispatcher::removeEventListener(EventListener* listener)
{ {
++iter; ++iter;
} }
if (isFound)
break;
} }
if (_listeners->empty()) if (_listeners->empty())
@ -193,6 +215,9 @@ void EventDispatcher::setPriorityWithSceneGraph(EventListener* listener, Node* n
if (item->listener == listener) if (item->listener == listener)
{ {
item->fixedPriority = 0; item->fixedPriority = 0;
CC_SAFE_RETAIN(node);
CC_SAFE_RELEASE(item->node);
item->node = node; item->node = node;
return; return;
} }
@ -216,7 +241,7 @@ void EventDispatcher::setPriorityWithFixedValue(EventListener* listener, int fix
if (item->node != nullptr) if (item->node != nullptr)
{ {
item->node->dissociateEventListener(listener); item->node->dissociateEventListener(listener);
item->node = nullptr; CC_SAFE_RELEASE_NULL(item->node);
} }
return; return;
} }
@ -259,7 +284,7 @@ void EventDispatcher::dispatchEvent(Event* event, bool toSortListeners)
} }
} }
removeUnregisteredListeners(); updateListenerItems();
} }
void EventDispatcher::dispatchTouchEvent(TouchEvent* event) void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
@ -331,7 +356,7 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
if (touchEventListener->onTouchBegan) if (touchEventListener->onTouchBegan)
{ {
isClaimed = touchEventListener->onTouchBegan(*touchesIter, event); isClaimed = touchEventListener->onTouchBegan(*touchesIter, event);
if (isClaimed) if (isClaimed && item->listener)
{ {
touchEventListener->_claimedTouches.push_back(*touchesIter); touchEventListener->_claimedTouches.push_back(*touchesIter);
} }
@ -355,14 +380,20 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
{ {
touchEventListener->onTouchEnded(*touchesIter, event); touchEventListener->onTouchEnded(*touchesIter, event);
} }
if (item->listener)
{
touchEventListener->_claimedTouches.erase(removedIter); touchEventListener->_claimedTouches.erase(removedIter);
}
break; break;
case TouchEvent::EventCode::CANCELLED: case TouchEvent::EventCode::CANCELLED:
if (touchEventListener->onTouchCancelled) if (touchEventListener->onTouchCancelled)
{ {
touchEventListener->onTouchCancelled(*touchesIter, event); touchEventListener->onTouchCancelled(*touchesIter, event);
} }
if (item->listener)
{
touchEventListener->_claimedTouches.erase(removedIter); touchEventListener->_claimedTouches.erase(removedIter);
}
break; break;
default: default:
CCASSERT(false, "The eventcode is invalid."); CCASSERT(false, "The eventcode is invalid.");
@ -373,13 +404,13 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
// If the event was stopped, return directly. // If the event was stopped, return directly.
if (event->isStopped()) if (event->isStopped())
{ {
removeUnregisteredListeners(); updateListenerItems();
return; return;
} }
CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), ""); CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");
if (isClaimed && touchEventListener->_needSwallow) if (isClaimed && item->listener && touchEventListener->_needSwallow)
{ {
if (isNeedsMutableSet) if (isNeedsMutableSet)
{ {
@ -444,16 +475,16 @@ void EventDispatcher::dispatchTouchEvent(TouchEvent* event)
// If the event was stopped, return directly. // If the event was stopped, return directly.
if (event->isStopped()) if (event->isStopped())
{ {
removeUnregisteredListeners(); updateListenerItems();
return; return;
} }
} }
} }
removeUnregisteredListeners(); updateListenerItems();
} }
void EventDispatcher::removeUnregisteredListeners() void EventDispatcher::updateListenerItems()
{ {
if (!_listeners) if (!_listeners)
return; return;
@ -461,16 +492,18 @@ void EventDispatcher::removeUnregisteredListeners()
auto listenerItemIter = _listeners->begin(); auto listenerItemIter = _listeners->begin();
while (listenerItemIter != _listeners->end()) while (listenerItemIter != _listeners->end())
{ {
auto removeIterBegin = std::remove_if(listenerItemIter->second->begin(), listenerItemIter->second->end(), [](const EventListenerItem* item){ for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end();)
return item->listener == nullptr; {
}); if ((*iter)->listener == nullptr)
for (auto iter = removeIterBegin; iter != listenerItemIter->second->end(); ++iter)
{ {
delete (*iter); delete (*iter);
iter = listenerItemIter->second->erase(iter);
}
else
{
++iter;
}
} }
listenerItemIter->second->erase(removeIterBegin, listenerItemIter->second->end());
if (listenerItemIter->second->empty()) if (listenerItemIter->second->empty())
{ {
@ -483,6 +516,29 @@ void EventDispatcher::removeUnregisteredListeners()
} }
} }
if (!_toAddedListeners.empty())
{
std::vector<EventListenerItem*>* listenerList = nullptr;
for (auto& item : _toAddedListeners)
{
auto itr = _listeners->find(item->listener->type);
if (itr == _listeners->end())
{
listenerList = new std::vector<EventListenerItem*>();
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()) if (_listeners->empty())
{ {
delete _listeners; delete _listeners;
@ -563,16 +619,24 @@ void EventDispatcher::removeListenersForEventType(const std::string& eventType)
for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter)
{ {
(*iter)->listener->release(); (*iter)->listener->release();
if (_inDispatch)
{
(*iter)->listener = nullptr;
}
else
{
delete (*iter); delete (*iter);
} }
}
if (!_inDispatch)
{
listenerItemIter->second->clear(); listenerItemIter->second->clear();
delete listenerItemIter->second; delete listenerItemIter->second;
_listeners->erase(listenerItemIter); _listeners->erase(listenerItemIter);
} }
} }
}
void EventDispatcher::removeAllListeners() void EventDispatcher::removeAllListeners()
{ {
@ -584,17 +648,29 @@ void EventDispatcher::removeAllListeners()
for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter) for (auto iter = listenerItemIter->second->begin(); iter != listenerItemIter->second->end(); ++iter)
{ {
(*iter)->listener->release(); (*iter)->listener->release();
if (_inDispatch)
{
(*iter)->listener = nullptr;
}
else
{
delete (*iter); delete (*iter);
} }
listenerItemIter->second->clear();
delete listenerItemIter->second;
} }
if (!_inDispatch)
{
listenerItemIter->second->clear();
delete listenerItemIter->second;
}
}
if (!_inDispatch)
{
delete _listeners; delete _listeners;
_listeners = nullptr; _listeners = nullptr;
} }
}
void EventDispatcher::setEnabled(bool isEnabled) void EventDispatcher::setEnabled(bool isEnabled)
{ {

View File

@ -110,6 +110,7 @@ private:
int fixedPriority; // The higher the number, the higher the priority int fixedPriority; // The higher the number, the higher the priority
Node* node; // Weak reference. Node* node; // Weak reference.
EventListener* listener; EventListener* listener;
~EventListenerItem();
}; };
/** Constructor of EventDispatcher */ /** Constructor of EventDispatcher */
@ -127,14 +128,18 @@ private:
/** Sorts the listeners of specified type by priority */ /** Sorts the listeners of specified type by priority */
void sortAllEventListenerItemsForType(const std::string& eventType); void sortAllEventListenerItemsForType(const std::string& eventType);
/** Removes all listeners that have been unregistered. */ /** Updates all listener items
void removeUnregisteredListeners(); * 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: private:
/** /**
* Listeners map. * Listeners map.
*/ */
std::map<std::string, std::vector<EventListenerItem*>*>* _listeners; std::map<std::string, std::vector<EventListenerItem*>*>* _listeners;
std::vector<EventListenerItem*> _toAddedListeners;
int _inDispatch; int _inDispatch;
bool _isEnabled; bool _isEnabled;