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.
Hello, Andre Rudlaff,
Could you provide a demo project for reproducing the issue?
should be easy to change the HelloWorld example for reproducing the issue.
I will create a demo project early the next week.
Attached is a modified HelloWorld project, which triggered the issue whenever I click on the screen.
I’ve added some additional output to the touch dispatcher class, which is also provided.
The modified HelloWorld is based on the 0.13 beta release.
This is the sample output for when the bug occurs:
// Application Startup
Create new Button: 0x7f22b0
Create new Button: 0x7f23f0
Create new Button: 0x7f2580
// Click into the Window
Touch Began for Button: obj3 (0x7f2580)
Touch Began for Button: obj1 (0x7f22b0)
// Touch Ended for obj1 will trigger switchButtons(), which will remove the added buttons and create new ones
Remove Delegate: 0x7f23c8
Append to m_pHandlersToRemove: 0x7f23c8
Remove Delegate: 0x7f2508
Append to m_pHandlersToRemove: 0x7f2508
Delete Button: 0x7f23f0 <— This is obj2 which is never added to the touch dispatcher, but we try to remove it
Remove Delegate: 0x7f2698
Append to m_pHandlersToRemove: 0x7f2698
Create new Button: 0x7f23f0 <— by pure chance the new button gets the same address as the previously deleted one
addTargetedDelegate() Retain Delegate: 0x7f2508 <— the touch dispatcher thinks the newly created button is within the list, but the reference was set by obj2 which has never been added
Create new Button: 0x7f51d0
Create new Button: 0x7f5310
Force Remove Delegate: 0x7f23c8
Delete Button: 0x7f22b0
Force Remove Delegate: 0x7f2698
Delete Button: 0x7f2580