DNESS / cocos2d-iphone

Automatically exported from code.google.com/p/cocos2d-iphone
1 stars 0 forks source link

TouchDispatcher retains target #523

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a CocosNode that register itself to TouchDispatcher
2. Add it to the scene
3. Remove it from the scene
4. It will be still alive and handling touches...

What is the expected output? What do you see instead?
TouchDispatcher should not retain targets. Targets should unregister themselves 
on dealloc if necessary. This is normal behaviour for 
delegates and targets throughout all NS and UI frameworks, and is Best 
Practices with Apple in general.

What cocos2d version are you using ?
HEAD (0.8.1-rc)

Please provide any additional information below.
Here's something that you might find useful for your arrays. It's a 
NSMutableArray creator that doesn't retain/release, but keeps all 
functionalities of NSMutableArray.
<pre>
@implementation NSMutableArray (WeakReferences)
+ (id)mutableArrayUsingWeakReferences
{
    return [self mutableArrayUsingWeakReferencesWithCapacity:0];
}

+ (id)mutableArrayUsingWeakReferencesWithCapacity:(NSUInteger)capacity
{
    CFArrayCallBacks callbacks = {0,0,0,CFCopyDescription,CFEqual};
    // We create a weak reference array
    return (id)(CFArrayCreateMutable(0, capacity, &callbacks));
}
@end
</pre>

I have already registered a couple issues in this direction. This causes lots 
of bugs in our game with each minor release drop.

Original issue reported on code.google.com by hans.lar...@gmail.com on 26 Aug 2009 at 3:58

GoogleCodeExporter commented 9 years ago
Oops...  although mutableArrayUsingWeakReferences is useful for other classes, 
it's not the case here. You 
should put the delegate property as assign. But then it seems to break a couple 
things...

Original comment by hans.lar...@gmail.com on 26 Aug 2009 at 4:22

GoogleCodeExporter commented 9 years ago
related issue: #422

issue #422 tried to fix this scenario (which is somewhat common):

1. create a node. register a Touch handler by inserting a Menu (let's call it 
NodeTH)
2. when the menu from NodeTH receives the ccTouchXXX it decides to removes 
itself
3. since the NodeTH retain count is 0, it's memory space is no longer reserved
4. but some removed instance methods will continue to run.

I've added a test (tests/bugs/bug422) that simulates this scenario.

Original comment by ricardoq...@gmail.com on 26 Aug 2009 at 4:34

GoogleCodeExporter commented 9 years ago
I use a Button class (which is a CocosNode) to handle events and it registers 
itself on init, unregister itself on 
dealloc. But it cannot get deallocated, since TouchHandlers retain it, so it 
gets called even if the scene isn't 
shown anymore...

Original comment by hans.lar...@gmail.com on 26 Aug 2009 at 4:38

GoogleCodeExporter commented 9 years ago
ok. the workaround is:
to register itself on "onEnter" and unregister itself on "onExit".

Original comment by ricardoq...@gmail.com on 26 Aug 2009 at 4:47

GoogleCodeExporter commented 9 years ago
@ hans,
dealloc should really be used to clean up memory the node has in use. This 
method is
not created to unregister itself from certain handlers. Instead as Ric suggests,
onExit is a perfect method for this.
I wouldn't see "onEnter" and "onExit" as a workaround but as the proper way to 
go
about it.
You never know how many things retain your object. Don't rely on the retain 
count for
anything.

Original comment by nash8...@gmail.com on 14 Sep 2009 at 7:07

GoogleCodeExporter commented 9 years ago
@nash

See here: 
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt
/Articles/mmObjec
tOwnership.html

Particularly this:
> Additional cases of weak references in Cocoa include, but are not restricted 
to, table data sources, outline 
view items, notification observers, and miscellaneous targets and delegates.

One notable exception would be NSTimer, which keeps a strong reference.

I think the TouchDispatcher is akin of the Target-Action pattern, which has a 
weak reference. Anyway, your 
documentation mentions this (retaining of target) already, so it's not really a 
problem. Hope this is constant 
throughout the cocos API.

Original comment by hans.lar...@gmail.com on 14 Sep 2009 at 3:26

GoogleCodeExporter commented 9 years ago
Thanks for the link. Had a good read (and a nice new bookmark).

I suppose that, as per your suggestion, weak references are an option for the
TouchDispatcher.
Although weak references are an option here, the object that no longer should 
receive
Touches, should first unregister itself with the dispatcher. So it won't fix the
issue of "still receiving touches when off-stage"
If the dispatcher holds a weak reference to the object, the object will have to
remove that before being released.

Source:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt
/Articles/mmObjectOwnership.html
Quote from Mac Dev Center: "[...] you need to unregister [the object] with the
notification center to prevent the notification center from sending any further
messages to the object, which no longer exists. [...]"

Also of interest perhaps: "[...] you should not design classes such that you are
assuming that dealloc will be invoked when you think it will be invoked."

Anyway, I think I've meddled too much already in this affair. I'll just leave 
it with
you guys.

Original comment by nash8...@gmail.com on 15 Sep 2009 at 8:23