not doing dealloc - iphone

i have this in the superview:
mySubView = [[MySubView alloc] init];
[self addSubview:mySubView];
[mySubView release];
then at some point later, in the sub view, this:
[self removeFromSuperview];
when i debug it, i notice that the dealloc for the subview is never called, even though i'm fairly sure the reference count should be 0. any ideas why this might be? thanks.

Yes, When you send removeFromSuperview, subsequently release message sent. And each call of release decrease retain count. And in case:
MySubView * mySubView = [[MySubView alloc] init];
[window addSubview:mySubView];
[mySubView release];
[mySubView removeFromSuperview];
the result will be as you expect: after removeFromSuperview mySubView's retain count became 0, and dealloc will be called.
but in your example there is more code behind "then at some point later" and some other object (and it is not superview) retains mySubView. You can for example log retainCount value to see where your view retained/relesed.

You can't rely on retainCount to provide any useful information for debugging. In some cases it may assist you, but the Apple docs say:
Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
To understand the fundamental rules of memory management that you must abide by, read “Memory Management Rules”. To diagnose memory management problems, use a suitable tool:
The LLVM/Clang Static analyzer can typically find memory management problems even before you run your program.
The Object Alloc instrument in the Instruments application (see Instruments User Guide) can track object allocation and destruction.
Shark (see Shark User Guide) also profiles memory allocations (amongst numerous other aspects of your program).

I don't know if removeFromSuperview does this, but the pointer in the superview needs to be released. If removeFromSuperview only releases the pointer in the subview to the superview and not the pointer in the superview to the subview, that may be the source of your problem.

i'm fairly sure the reference count should be 0.
Are you? Why?
Forget retain counts. Think only in terms of object ownership because retain counts are almost completely meaningless as an aid to debugging memory management.
Apple provides lots of tools for debugging memory management issues. Use them.
This link might be helpful.
http://developer.apple.com/iphone/library/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingPatterns.html

Related

Cocoa touch - Memory Management

I am a former java programmer, and I am having some troubles managing the memory on cocoa touch.
In fact, I think I got the retain/release trick, but still I am not sure I got it right.
For example, I am creating and adding a subview to the main window:
aViewController=[[AViewController alloc]init];//aViewController is (nonatimic,assign), so retaincount = 1 after this line?
[self.window addsubview aViewController];
[aViewController release];//retaincount=0?
And in aViewController I have an IBAction:
[self.view removeFromSuperView];
How can I be sure the object aViewController gets completely 'deleted' and memory released after I removed it from superview (think that controller as a graphic-heavy view controller)?
Also, generally, is there a way to be sure an object is deallocated? I am aware that if I ask ownership of an object I have to release it at a certain point, but what if I just want the object's pointer to be null at a certain point(not basing on the retaincount)? Should I call dealloc directly? I find sometimes very confusing to keep under control the retain/release mechanism.
If someone could give me a quick breakdown to make my mind 'click', i would be extremely grateful.
Thanks.
The short answer is you shouldn't worry about when an object gets deallocated (unless you are debugging a memory management problem). You should just worry about ensuring that if your code retains, copies or inits an object, it releases or autoreleases it. By doing so you will ensure reference counts are properly maintained and hence deallocation will be managed for you.
Leave the task of deciding when to dealloc an object to the runtime. Never call dealloc directly unless you are calling the super classes dealloc method at the end of your objects dealloc method.
Also, don't even look at the retain count property of an object. Various pieces of the framework manipulate those too during the lifetime of the object, and you'll see that number move around seemingly at random. It'll just drive you nuts.
The really important thing is to make sure you've got the objects retained that would be a problem if they went away suddenly, and released when you're okay with them going away suddenly.
aViewController=[[AViewController alloc]init];retainCount is 1
[self.window addsubview aViewController.view];retainCount is 2 (adding the view increments the retainCount)
[aViewController release];retain count decrements to 1;
[aViewController removeFromSuperView];retain count decrements to 0;
Now the dealloc method will be called the allocated memory will be freed. This is what have understood please correct me if i am wrong i always find difficulties during memory management.

Should I release an UIImageView added to my view if I will detect touch on it later on?

I've learnt that if you create an object, you own it and need to release it when you're done with it. In this case I create an UIImageView and add it to my view like this:
myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image.png"]];
[myImageView setFrame:CGRectMake(10,10,100,100)];
[self.view addSubview:myImageView];
[myImageView release];
If I later on want to detect touch on myImageView like this in my touchEnded-method:
if([touch view] == myImageView){
NSLog(#"TOUCHED!");
}
This works, but is this correct, since I now used myImageView after releasing it?
And how do I release myImageView from the self.view that I added it to earlier?
The cardinal rule of Cocoa memory management is that you should retain those things you care about, and release those things you do not care about. There are a very small number of exceptions to prevent retain loops (delegates and datasources are never retained), but this is the rule you should follow.
In this case, if you are storing the image in an ivar, I would continue to retain it, regardless of the fact that its superview will always retain it, and so you don't "have" to. But if the view is removed from its superview, you will wind up with a dangling pointer, and then you will crash, so I code defensively against that by retaining. If you used an accessor here (which you should), then this would be automatic and much safer.
Apple has grown more consistent about this in iOS, switching their recommendation about IBOutlets. On Mac, you do not retain your IBOutlets, but in iOS, Apple explicitly instructs you to do so. This is similar to the situation you are discussing, and I agree with Apple's move towards a safer approach.
As long as your myUIImageView object has a retain count > 0, it will still exist and you can continue using it. When you first add it as a subview, it gets a retain message so it's retain count is likely 2. Then you send it release, so its retain count is reduced to 1. This means it still exists in memory. Now, if you sent it release again, or sent it removeFromSuperView then its retain count would be zero, and you'd lose it.
The behavior is erratic, sometimes you may see it works, sometimes you get a crash.
If you want to use that variable to point to your image view, retain the ivar (by using a retain property). This way you ensure that the image view is available for your controller class to use.
Assuming myUIImageView is an ivar of your custom UIView subclass, your code will work as long as your image view stays in his superview. The image view instance may be deallocated and you may end with an invalid pointer referencing a deallocated object. At best you crash.
According to memory management guidelines, you should consider your image view <-> custom uiview subclass relation as wether:
strong reference. You own the image view (as you created it), and are responsible for retaining / releasing it
weak reference. You don't own the object, thus keeping a reference to it may be dangerous.
in your case, it's probably a strong reference. your myUIImageView ivar should be a nonatomic retained property of your object.
If you need to access your UIImage at some point in the future, you need to retain it.
How you do this is at your discretion, but you should not rely on the UIView to retrain your objects for you. The situation you've created works for now, but it's fragile.

Cannot allocate new instance of UIView subclass after deallocating

I have an instance variable *TangramLevel(:UIView) currentLevel; in my viewController class, and I have an instance allocated at start (it's retainCount 1). I attached it to the view [self.view addSubview:currentLevel]; (retainCount 2).
When the level finishes, it notifies the controller, so controller removes it from the view [currentLevel removeFromSuperview]; (retainCount 1), and release the allocated instance - [currentLevel release]; -, to have it deallocated (retainCount 0 = invoke dealloc).
Then on the next line, controller wants to allocate/addSubview a new level instance with another level data, but the application crashes (EXEC BAD ACCESS).
If I don't release currentLevel after removeFromSuperview, the appliaction works, but I have an unused level instance left in memory then, which is also a problem (the main problem itself).
Is there any bug in the method I wrote above? Or the bug is elsewhere, maybe in the level class? I allocated some UIImageView in the level, but I release every allocated object in the levels dealloc method. Any ideas?
Post your code.
This is definitely a memory management issue. The question is "where is the problem created?" To answer that, we need to examine the following:
Your "currentLevel" iVar handling code (do you used synthesized properties, etc.). Post it.
How are you assigning the view to currentLevel?
Where are you releasing this, specifically?
How is your view's dealloc implemented (what do you release and how)?
Is there any other code that retains/releases this view or anything related to it?
The fact that you're calling release in your "I'm done with this level, let's swap in the next" code suggests an overall design issue. Make the memory management of each of a class's iVars the responsibility of its accessors and ONLY use the accessors to interact with it (even from within the class/instance). With synthesized properties, this makes it brain-dead-simple. That way you don't have to worry about where to retain/release iVars because it's always funneled through the accessors.

iPhone - insertSubview makes ObjectAlloc jump

Whenever I add a new viewController my ObjectAlloc jumps up really high and never comes back down. Even after calling removeFromSuperview. Is this normal?
if((UIButton *) sender == gameArcadeBtn) {
GameArcade *gameArcadeController = [[GameArcade alloc]
initWithNibName:#"GameArcade" bundle:nil];
self.gameArcade = gameArcadeController;
[gameArcadeController release];
[self.view insertSubview:gameArcadeController.view atIndex:1];
}
Instantiating a view always creates many objects.As long as this view is in memory or has not been autoreleased, the objects will remained alloced in memory. Thus, to answer your question, this is normal.
It sounds like you are worried about memory usage and while it is important to watch the object allocs so that it doesn't get too it is more important to find your app leaks.
Some memory management tips:
1) do lazy loading. Only load your views when the user asks for them, not all at the beginning of the app
2) remove everything that you possibly can when you dont need it anymore. This means doing tons of work in viewWillAppear and viewDidDisappear
3) learn about #properties and how it relates to autoreleasing, and do not use properties for everything.
4) As appealing as it is, avoid autorelease and manually release objects when you dont need them anymore.
that's probably due to the fact that you're still retaining the view's controller in the class. try releasing that

NSObject release... Still shows up in ObjectAlloc

I have been tracking down why NSObject references, while being explicitly release, still show up in ObjectAlloc. In fact, have reduced down NSObject to a basic shell, with a [[myObject alloc]init] immediately followed by a [myObject release], and it does not look like it is being released in ObjectAlloc. This is a big problem with a NavigationController app that pushes/pops multiple view controllers, as the recently popped viewcontrollers aren't being released, because of these 'unreleased' NSObject references. Hmmmmmm.
I could put my code up here, and have a bunch of 'have you's that never get anywhere. Autorelease pools, blah blah.
So, let's look at the Sample 'SeismicXML' sample app from Apple... fire it up in ObjectAlloc/Leaks. Very basic in getEarthquakeData:
XMLReader *streamingParser = [[XMLReader alloc] init];
[streamingParser parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];
[streamingParser release];
I see a TON of junk laying around in ObjectAlloc from XMLReader, despite releasing it. I bet if we put a 'refresh' button on this app to call 'getEarthquakeData' again, we would crash the app within 5 refreshes.
Any thoughts?
I think you are confused about the ObjectAlloc instrument which will show all object allocations for the lifetime of your application. It's main use is to track memory usage over time.
The instrument I think you want is the one that is called Leaks which shows you what memory is being leaked by not having any reference to it. That is pointers to objects not being sent release-dealloc before they are reassigned.
There might be an autorelease pool holding onto the object. If you create many autoreleased objects without cleaning them out of the pool, you'll get leaks until you return to the outer loop with the autorelease pool.
Here's how autorelease pools work: in the main loop, there's an autorelease pool. Everything autoreleased goes there. At the end of every loop iteration, all the objects in the pool get released. If you allocate objects in another loop somewhere, they won't actually get released until you return to the main loop. Unless, of course, you create your own autorelease pool just for the loop.
Another problem could be that your object is never released. If you get an exception between +alloc and -release you'll get a leak. A way to fix this is to use instead:
[[[XMLReader alloc] init] autorelease]
Finally, you could be working with garbage collection here. I don't know enough about the GC system to tell you what behavior you should expect.