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
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::string, std::vector<EventListenerItem*>*>();
}
std::vector<EventListenerItem*>* listenerList = nullptr;
auto itr = _listeners->find(item->listener->type);
if (itr == _listeners->end())
if (_inDispatch == 0)
{
listenerList = new std::vector<EventListenerItem*>();
listenerList->reserve(100);
_listeners->insert(std::make_pair(item->listener->type, listenerList));
std::vector<EventListenerItem*>* listenerList = nullptr;
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->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<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())
{
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)

View File

@ -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<std::string, std::vector<EventListenerItem*>*>* _listeners;
std::vector<EventListenerItem*> _toAddedListeners;
int _inDispatch;
bool _isEnabled;
};