Memory Management In iPhone - iphone

I have an iPad App which shows a whole load of information and related images. For instance: I can access to the section “Events”, from which I can choose one. Every single one has different dates or side events. Once I choose the side event, I charge some small views, which contain the title of the news; a small image as a preview and a short text in a ViewController (which has a ScrollView). This previews can be a lot. There are no leaks due to my code (I analized with Instruments and the only ones I can find are due to NSXMLParser bug), but I have noticed that the live bytes don’t slow down, ever, they only grow. Every time I have to update the content of the ScrollView I take care of inserting the following code:
if ( bannerVideo ) {
[banner release];
banner = nil;
}
Do you by any chance know what could be the reason for such a constant growth?

SOLVED
I added the ViewController "bannerVideo" as a subview to the main ViewController. This causes the retainCount to increase by one. So, when I asked for a new view:
if ( something ) {
[[bannerVideo view] removeFromSuperview];
[bannerVideo release];
bannerVideo = nil;
}
Yes, the main access to the heap area for bannerVideo was released, but it was still retained by the main ViewController View.

Related

Custom KeyBoard get terminated due to memory pressure in iOS 8

Custom KeyBoard get terminated due to memory pressure in iOS 8
Initially my custom keyboard is taking around 25mb of memory, but this memory is not deallocated with I dissmiss the keyboard. Memory keep on increase when we open custom keyboard again and again and finally terminated due to memory pressure.
Help me out with this issue?
You can dealloc some things in ViewWillDisappear function of KeyboardViewController
The keyboard extension runs in a process that persists after the keyboard disappears. Your keyboards view controller is created anew each time your keyboard is created, but the process that view controller is in persists. So free memory when your view controller is closed. If you are using images you won't want to use imageNamed: you will want to use imageWithContentsOfFile:. Because UIImage uses a cache for imageNamed that will persist.
I have tried tons of ways to avoid this famous memory accumulation issue, but according to my long long trial & errors, the best and the simplest way to free all memory before a keyboard disappears is to call exit(0) in viewWillDisappear of KeyboardViewController.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
exit(0);
}
[Update] exit(0) was perfect to release all memory since it kills the keyboard extension process. Unfortunately it seems like killing the process makes iOS unstable.
Consequently, the most stable way is to release all allocated objects as much as possible in viewWillDisappear. For example,
For all custom views and all custom view controllers
Remove all strong references of the views and the view controllers, such as subviews, constraints, gestures, strong delegate, and so on.
[aView removeFromSuperview];
[aView removeConstraints:aView.constraints];
for (UIGestureRecognizer *recognizer in aView.gestureRecognizers)
[aView removeGestureRecognizer:recognizer];
Set nil to all object properties of the view controllers.
aViewController.anObject = nil;
For other big custom objects
Remove all added objects from all arrays, dictionaries, and so on.
[anArray removeAllObjects];
Do not cache images using imageNamed:.
If well released, memory usage while debugging would not be increased or very slightly increased(<0.1MBytes per dismissing). If memory usage is increased after many dismissing even though custom objects are released as much as possible, exit(0) can be called periodically with some risk of unloading.

Do the viewcontrollers in a UIPageViewController set-up need releasing?

I am using the Apple UIPageViewController template from Xcode to create interactive photobooks. Everything works fine except that whenever I turn a page (create a new viewcontroller) the memory allocation goes up and up and up until the app crashes. It looks to me that the viewcontrollers never get 'released' (am I still allowed to use that word in an ARC environment?). It does not seem to be anything to do with the content of the pages because when I comment out all the content creation stuff in the ...DataViewController the memory still keeps going up and up every time I turn a page, not as spectacular as when a large image has been included but it still keeps creeping up.
There's been exactly the same question here: PageViewController: How to release ViewControllers added to it? but this one deals with a pre arc & storyboard situation. Adding autorelease is not permitted and it certainly seems that the compiler is NOT taking care of it. :-(
Any suggestions?
The problem turned out to be the never enough damned "UIImage imagedNamed" construct. It probably is all my own fault for not checking after I read somewhere that this had been fixed in a recent xcode release. So I assumed images were no longer being cached whereas the opposite was true. Once I changed all to the "UIImage imageWithContentsOfFile" the app started working smooth as a babies bottom.
I had the same problem building a picture book with very large images. I went to other question you provided a link for and that solved it for me. Adding "autorelease" frees up the memory.
In the UIPageviewcontroller delegate method "viewControllerAtIndex". I changed from:
// Create a new view controller and pass suitable data.
ContentViewController *contentViewController = [[ContentViewController alloc] initWithNibName:#"ContentViewController" bundle:nil];
and added autorelease
// Create a new view controller and pass suitable data.
ContentViewController *contentViewController = [[[ContentViewController alloc] initWithNibName:#"ContentViewController" bundle:nil] autorelease] ;
This wasn't included in the apple example but I'm also using xib for each page. I've been debugging this using instruments and saw memory reclaimed right away and dealloc being called when it wasn't previously.
found answer here....
https://stackoverflow.com/a/7934392/1212585

UINavigationController: Release ViewController's memory when popped

I have seen a few posts on this subject here on SO, but no definitive answers. Here is my problem.
I have a UINavigationController which I use as a gallery. On the first controller I load up a bunch of remote images. This increases my memory size, but not by that much. When clicking an image, it will push on another viewController which has images for the gallery just clicked. This might load in another 1MB or more of data from those images.
The problem here is that a user might browse any number of these galleries. Since when I pop the viewController, that memory is not released I start to get too much memory usage in my app when the users continues to browse the galleries.
Is there any way that I can release this memory when I pop my viewController? Perhaps in my viewDidDisappear: method? If so, what would I release? And how can I create it again? I tried this to a point, such as releasing my view, but I get crashes.
Any insight into this issue?
PhotosGalleryiPad *gallery = [[PhotosGalleryiPad alloc] init];
gallery.items = self.items;
gallery.asset = self.currentAsset;
[self.navigationController pushViewController:gallery animated:YES];
[gallery release];
You normally release any memory in the dealloc method of the view controller that gets popped off the stack.
However, if you're talking about images and you loaded them with [UIImage imageNamed:] then UIKit may be caching them. Try faking a memory warning in the simulator (from the Hardware menu) and see if that unloads these cached images.
You can also do a heapshot analysis in Instruments. Mark the heap before loading the view controller, mark it again after closing the view controller, and see which objects stick around.
Where, exactly, are you retaining these gallery images?
Let me take a guess that gallery.items is a mutable collection (possibly an array) holding the images. As the user visits new galleries, more images are added to this array. From view controller to view controller, you are passing a pointer to this array:
gallery.items = self.items;
So, when you pop the view controller, you are still left with the same, enlarged, array. The issue, then, is how to cull this array of the newly added images when you pop a view controller.
Rather than passing a pointer, you could make a shallow copy of the collection. If it's a mutable array, you could do as follows:
gallery.items = [self.items mutableCopyWithZone:nil];
Then, when a view controller is popped, its items array is released. The objects added by the popped view controller are released, but the old objects are still retained in the previous view controller's items array.
(I'm just taking a guess. If I'm wrong, it would be helpful if you explained where you're retaining these images.)
If you are "popping" views onto the foreground like this:
infoScreen = [[[infoScreen alloc] initWithNibName:#"InfoScreen" bundle:nil] autorelease];
infoScreen.view.center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
[self.view sendSubviewToBack:self.view];
Then you would do [infoScreen release];
to release/free the view from memory.
Remember anything you alloc, or retain (there are other situations too but i forget them off hand) you need to release.

how to "prepare" a view in the background?

I have a two views, 1st is a simple view with some introduction about usage and by click of a button it opens the main view. The main view has many images and two customized tables with rows consists of text and image, thus the creation of the main view is quite slow. The profiler shows most of the time is consumed by imageIO (decode_mcu, png_read_filter_row, pmap_copy_page and decompress_onepass)
I want to optimize by creating the main view immediately after the 1st view is loaded, and when I click the button, it simply set that view to visible or bring that view to front.
I tried to alloc & init the main view in the first view's viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
rootVC = [[RootViewController alloc] initWithNibName:#"ViewController" bundle:nil];
rootVC.delegate = self;
}
and do this in the button's action method
- (IBAction)buttonUp:(id)sender {
[self.view addSubview: rootVC.view];
}
But this is not working, the loading still takes very long. How could I sacrifice some memory to make better user experience?
Thanks
Leo
You should:
Use Instruments to see where your code is spending the most time, and optimize there. It may not be where you think.
If you are using a UITableView, learn how to create UITableViewCells on demand (rather than preloading a large number) and recycle instances (rather than recreating them).
Only if Instruments points to this as the bottleneck: try loading/decompressing images in on a background queue, then updating the UIImageView (or whatever) on the main queue after loading.
In iOS 4.x or later, you can do this:
NSString *path = ...
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
// This is happening in the background thread.
UIImage *image = [UIImage imageWithContentsOfFile:path];
dispatch_async(dispatch_get_main_queue(), ^{
// This is happening on the main thread; all UI updates must happen here.
imageView.image = image;
});
});
P.S. By the way, UIViewController doesn't load the view on creation, but on demand. So based on your code above, the expression rootVC.view is probably triggering the view to load. If you want to force it to load earlier, just put rootVC.view somewhere else.
UIViewController tries to load its view lazily, i.e. the view isn't loaded until it's actually needed. If you really want to force your view controller to load its view, you just need to access its view property, e.g. rootVC.view.
However, you really shouldn't need to do that. Table views, for example, only create the cells that are visible on screen, so it's unlikely that the number of rows is significantly impacting the time to load the view. One caveat here is that there are some things that can really slow down a table view. For example, if you're using variable-height cells in a table with a lot of rows, that can really slow down table creation. Try not to do that.
#benzado gives some good pointers for improving performance. Trying to work against Cocoa-Touch is always a recipe for pain, so try instead to figure out why your view is taking so long to load. Where is your app spending all that time? What can you do to reduce that load?

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