How to persist values after a memory warning viewDidUnload - iphone

My problem is when I use the camera UIImagePicker and the phone is low on memory. It throws a memory warning and unloads the view and then reloads.
I know this is a very common problem and many questions are already in SO. I'm not going into this.
- (void)viewDidLoad
{
[super viewDidLoad];
MyPersonClass *persons = [[MyPersonClass alloc] init];
persons.images = [NSMutableDictionary dictionaryWithCapacity:4];
....
...
}
My issue is the my view controller has four buttons and UIImageViews and when I tap each, they open the camera and image clicked is shown back in the UIImageViews and these images are also stored in the persons.images NSMutable Dictionary.
Sometimes it throws the popular error of memory warning and Unloads the view and this removes all the images in the UIImageView which were taken before the memory warning and I lose everything in persons.iamges I just want to be able to retrieve this data back. I don't know where to store it (I don't want to use CoreData for this).

You can maintain instance variables for storing image when viewDidUnload gets called. set a flag in viewDidUnload and then store all the images of your Imageviews. And in viewDidLoad check the flag that if viewDidUnload was called then assign the saved images to your ImageView.

You can save your MutableDictionary as a plist in the sandbox's application like that
[yourMutableDictionary writeToFile:pathToSave atomically:YES];
And then, get your NSMutableDictionary by this way
NSMutableDictionary *containOfPlist = [NSMutableDictionary arrayWithContentsOfFile:pathToYourPlist];
Hope this is what you want.

please use the NSCache for storing the images with KeyValue pair.
On the memory warning write the NSCache object to file and clear all objects from NScache object on low memory warning call back.
on loading application again rad the NSCAche from that file.
so i that manner you can save the data and can use it back.
another alternate option is to take NSDictnaory and store it via using NSArchiver class.

Related

Memory leak while using MWPhotoBrowser

I am using MWPhotoBrowser in my app.
Here is the delegate method which is called when I view photo in gallery:
-(MWPhoto*)getPhotoFromArray:(NSArray*)array atIndex:(int)index{
ImagesDb *imageObj = [imagesArr objectAtIndex:index];
ImagesDataDb *imageData = imageObj.data;
MWPhoto *photo = [[MWPhoto alloc]initWithImage:imageData.orignalImage];
return photo;
}
ImagesDataDb and imagesObj are CoreData Object
Everything is fine, but as I browse photos memory gets filled (as previously images were not released )
Ultimately , the app crashed due to memory problem.
I believe that "ImagesDataDb" object(this object containd image in detail) gets alllocated in memory but It doesnt gets deallocated, even though the reference object(MWPhoto object in this case) to it gets deallocated.
This means that object previously allocated doesnt leave memory.
Whats the solution to this problem ?
Oh yes, I got it now.
I simple added the line
((ImagesDb*)[imagesArr objectAtIndex:index]).data = nil; to my code.
Now, what happens is that it deallocates the memory which was used by the object.
Anyways , thanks for the answers

UIViewController doesn't seem to be fully released with ARC

The first view inside my application will only need to be shown once.
I am using the following inside a custom segue, to get it off the Navigation Controllers Stack and transition to the new one:
- (void)perform {
UINavigationController *nav = [self.sourceViewController navigationController];
NSArray *viewControllers = [NSArray arrayWithObject:self.destinationViewController];
[nav setViewControllers:viewControllers animated:YES];
}
While I was able to confirm, that the dealloc method gets called, the memory usage doesn't go down. I am 100% certain, that the memory was allocated by the ViewController, that I would expect to be released, since it contains a pretty big image (UIImageView) and the other view controller is tiny (memory-wise).
I am also sure, that I am not holding any references to the contained elements anywhere else.
Could it be that UIImageView keeps the image in memory, in case it would be needed again?
Is what I am doing even a good way to go? (I was inspired by this)
As a result of a quick test, I infer that image views that have images set in Interface Builder appear to be doing some caching. I assume it's the same caching mechanism used by imageNamed, whose documentation says:
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.
I don't know of any way to simulate the memory pressure that will cause this cache to be purged (other than obviously doing sufficient allocations to result in actual memory pressure). The various caches don't generally respond to the simulator's "Simulate Memory Warning" strangely enough, even though they do respond to true memory pressure. (Besides, you're testing on physical devices because of location services.)
But you can test to see if this indeed the issue by not setting the image in Interface Builder, but rather do it programmatically (and do it without using imageNamed), e.g.:
NSString *path = [[NSBundle mainBundle] pathForResource:#"imagename" ofType:#"png"];
self.imageView.image = [UIImage imageWithContentsOfFile:path];
In my test, when I dismiss a scene in which the image was set in Interface Builder, I do not recover as much memory as I do when I use the above code instead.

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.

Shared UIImageView for background image throughout app - Singleton Property

I have a UIImage that I use throughout my app as a background image for grouped UITableViews.
I thought that for efficiency I would alloc and init the UIView with my UIImage in my appDelegate and then access throughout my app. That way I would only allocate that imageView once and if I was drilling into a nav stack with multiple tableviews with this image I wouldn't need to worry about releasing and restoring the image as I descend and ascend or incur overhead at each step.
As soon as I tried this I noticed that it seems that the UITableView class is releasing the my shared image down to 0 and it therefore is going away. Makes perfect sense but I would need to prevent the image from ever hitting a 0 retain count for this to work.
Is this a totally goofy approach?
If it is not what's the best way to retain my shared ImageView? I know I could call retain when I setup each tableview's backgroundimage but I was wondering if there is a way to set the retain count of the shared UIImageView to NSUIntegerMax in my appDelegate. I've setup singleton classes before but in this case I'm trying to have a single property that is never released rather than creating a UIImageView singleton subclass.
Sorry if that's a little muddled and thanks for any pointers.
I would not worry so much as + (UIImage *)imageNamed:(NSString *)name are cached.
From the spec:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.

Need Help on didRecieveMemoryWarning in 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: