Need Help on didRecieveMemoryWarning in iPhone - iphone

I am developing an application which has almost 12 view controllers. Application has tabBar with 4 tabs means four view controllers and there are multiple views to navigate in each tab bar. Please note each tab has a navigationController with a rootviewController being its firstview. Application is an extensive database application. When I run on simulator it works nice but get didRecieve memory warning while running on the device. I have few questions regarding the same.
NOTE: I have checked the application using Instruments tool for Leaks and there are no red pyramids which means there are no leaks in the code.
What is the best practise when you deal with multiple view controllers.
when I recieve memory warning, I call [self deleteObjects] which deletes all the instances which are retaning the values for the current controller. But I am not confident if this the right way. What should be done when we recieve memory warnings. Is there any good tutorial for that. (Links plz)
Also how to make sure that the [self deleteObjcts] is not called for the visible controller.
(I was calling the deleteObjects method in viewDidUnload method before but since we do [super didRecieveMemoryWarning] it breaks the code as viewDidLoad is called in hierarch from top to bottom so once I deleted object for top viewController obviously there will be error for rest of the controllers.)
Some of the basic confusing questions for me are as follows:
Why the memory warnings are not consistent. Like I get them sometimes at the start whereas sometimes there are no warnings.
When we used [NSDate date], [UIImage imageNamed:#"..."], [NSString stringWithFormat] etc, we dont own these objects and we dont have to release them but how can we make sure these objects are relased when we recieve a memory warning.
I am using NSMutableArray at multiple places. In this arrays I store the [NSString StringWithFormat ], [UIImage imageNamed...] objects, so when I realease the arrays do I need to relase the objects in the arrays though I dont own them.
Though this is a big list of question but I appreciate your help and time since I am in last stage of my development I am facing these major challenges.

You receive memory warnings when you run out of memory. Memory is not only taken by your App, all other running processes use memory and the memory being used may always vary.
Those object are all autoreleased. The NSAutoreleasePool will take care of releasing the objects, you should never release such an object yourself (well, not as long as you have not retained it yourself). This doesn't really matter, autoreleased object will be released quite quickly.
When putting an object in an array, it will be retained. When you release the array, it will send release all it's children objects. As you store autoreleased objects in the array, they will take care of their own releasing. This has probably already happened when you release the array, so -dealloc will be called on all the objects immediately.
NSMutableArray *someArray = [[NSMutableArray alloc] init];
NSDate *date = [NSDate date]; // Autoreleased object. Retain-count is 1
[someArray addObject:data]; // The array retains the data object. Now has a retain-count of 2
// Some other things
// The date object has been called release at some time (because it was autoreleased)
// so date now has a retain-count of 1
[someArray release] // Will release all containing objects thus date will be called dealloc

I've run into memory problems with UIImage imageNamed that I think are caused by the OS caching images and not releasing them when it should. There are lots of other developers who have seen the same thing.
I would try using imageWithContentsOfFile instead of imageNamed and see what happens.
For example forPNG images --
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"filename here" ofType:#"png"]];
Here's a thread that covers what I'm talking about:

Related

retain count of a view controller not equal zero after a release message

I have a view controller initialized like this: HomeViewController *homeVC = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
Then I've placed this method after I finished working with this view controller: [homeVC release]; and right after it i've placed NSLog#("%d",[homeVC retainCount]); the console displays 15 as a retainCount number, however, I put double [homeVC release]; lines and the same NSLog statement, result = app crashes ...
two questions:
1) can anybody explain that ?
2) how can I make the retainCount to be equal Zero ?
Various parts of code internal to the iOS SDK can/will retain your view controller as well, particularly if you are pushing to it, presenting it modally, associating it with a tab control, or doing pretty much any other nontrivial thing with it. In short, you are not the only one making use of your view controller. And your crash happens simply because adding the second release causes the view controller to eventually be released one too many times.
Moreover, manually inspecting the retain count of an object is not generally recommended, specifically because of cases such as this where the actual value does not match the value a developer might expect.
By matching every alloc/init, retain, and copy with a call to release, and by not worrying about precisely when the retain count reaches exactly zero (if you really want to know when this happens, set a breakpoint in dealloc). You have to write code that does not leak or over-release objects, assume that the iOS SDK will do the same, and trust that your object will be released at the correct point in time. Alternately, switch to SDK version 5 and use automatic garbage collection instead.
Do not use retainCount. It is meaningless. Just follow the memory management rules, release when you're the owner, and you will be OK.

not doing dealloc

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

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.

Memory Usage on convenience method vs init method

Recently when I looked into iPhone memory management, I tried to compare the convenience method and init method on the same object. For example, I have UIImageView where it displays a downloaded NSData:
Convenience method:
imageView.image = [UIImage imageWithData:[downloads dataAtIndex:0]];
init method:
UIImage *aImage = [[UIImage alloc] initWithData:[downloads dataAtIndex:0]];
imageView.image = aImage;
[aImage release];
When I try to go back and forth on the views to increase the memory usage and hit "Simulate Memory Warning", the memory usage for the app went from 20MB to 18MB with convenience method, and init method went from 20MB to 13MB immediately.
I also waited and interacted with the app to give time on releasing on the convenience method's autorelease. But it didn't drop much.
Other than the autorelease vs release, what else contributed the difference?
Your autoreleased objects created by the convenience methods will not be released until the containing autorelease pool is drained. It is advisable to wrap memory intensive operations inside of an NSAutoreleasePool block if you will be making heavy use of them.
The only difference that could be causing this is that imageWithData: doesn't use the system image cache, while initWithData: does. So maybe the image that's made with the initializer can release it's image data when it receives a memory warning since it can go back to the system cache, while the one that's created by the convenience method can't.
Objects created with convenience methods are autoreleased, as I am sure you are aware. However, if you have no AutoReleasePool in the RunLoop where you are creating the image, then the object will be added to a non-existent pool, and never properly cleaned up. This may be the case if you are running in a thread, and have forgotten to create an AutoReleasePool for that thread.
To verify if this is the case, you could run Instruments (Leaks) and see what it reports.
Something that I have noticed is that with autoreleased objects, under memory pressure, there is a system GC that occurs with a noticeable performance hit if you don't release your pools in a timely fashion.
Also, using the init / release method allows your memory consumption in loops to remain flat, while using a autorelease pool creates spikes. In some memory challenged contitions, the rapid increase of objects in the autorelease pool may cause your application to get booted before the system takes steps to clean up stuff like emails being open, mobile safari tabs, and iTunes stuff running.
Bottom line, I tend to use init more because it makes my application's memory consumption more consistent and I see fewer problems with getting booted randomly. The gradual increase in memory consumption lets the daemons clean up the system without killing my app. Finally, as somewhat of an aside, if you are using the #property keyword in your classes, you have to be careful with stuff like:
myProperty = [NSMutableArray arrayWithCapacity:10];
Because what will happen is when the pool in your main.m class gets collected that item will be gone, causing a crash due to calling a method on a released object. If you are setting it with #property (nonatomic, retain) you will want to use:
self.myProperty = [NSMutableArray arrayWithCapacity:10];
to make sure it hangs around. You can avoid all of that by just going with alloc init however. Just watch your reference counts to make sure you don't have double references causing memory leaks.