We had a strange bug today, that sometimes a touch delegate wasn’t added to the touch dispatcher correctly.
It turns out, the reason for the issue was the delayed removal of touch delegates. When the remove is requested while the touch dispatcher is locked.
The m_pHandlersToRemove array does not retain its elements, therefore the pointer may be resued by another object.
Note, that the bug only occurs when the removed delegate is NOT added to the dispatcher.
The issue is not really reproducable, so I try to explain what happens:
We have an object implementing the TouchDelegate protocol, which is NOT added to the touch dispatcher.
Lets call this object obj1.
There is another object (say obj2) which has been added to the touch dispatcher.
The user clicks on obj2. Within the onClick() method the following happens:
obj1 and obj2 are removed from the scene graph.
Their onExit() is called and both are removed from the touch dispatcher.
obj1 and obj2 are released.
Because obj2 is still retained by the touch dispatcher it is not immediately destroyed.
However obj1 is not retained by the touch dispatcher, therefore it is destroyed.
m_pHandlersToRemove now contains two objects (obj1 and obj2).
At this point obj1 is already an invalid reference.
Still in the touch callback a new button is added (lets call it obj3)
Now it MAY happen, that this button receives the same address as our free’d obj1.
Therefore the addDelegate() method will remove the pointer from m_pHandlersToRemove and return.
=> obj3 is never added to the touch delegate.
I must admit that the initial error is within the client code (obj1 is removed from the dispatcher, but never added). But I think this situation should be handled by the framework.
I’m not sure if there is a better solution, but enforcing that every CCTouchDelegate should be a CCObject and release/retain the object when it is added/removed to the m_pHandlersToRemove array should fix the issue.
The same issue may apply with the m_pHandlersToAdd. Probably it is never triggered there as the object isn’t deleted before it is really added to the dispatcher.