Memory leak while using MWPhotoBrowser - iphone

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

Related

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.

How to persist values after a memory warning viewDidUnload

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.

Managing memory for popover controllers and their content views

When the user taps on the right callout accessory on my map view's pin's callout I am showing a popovercontroller with a view inside it. I am maintaining 2 retained properties in the mapcontroller for this. I am also releasing these properties in dealloc of the mapcontroller - which probably never happens.
When the user deselects the annotation view I want all this memory released, does assigning nil suffice?
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
[self.informationViewController.view removeFromSuperview]; //remove from popovercontroller
self.informationViewController = nil;
popoverController = nil;
}
Yes, it should. This sets the reference of the object to nil which in turn releases the object. I'm no expert on memory management though, so if anyone wants to downvote/correct me, feel free.
I believe you also will need to release the objects.
Wouldn't just assigning nil only remove your pointer to the object in memory? I suspect the object would still reside in memory and still have a retain counter assigned to it, so it will not be removed from memory until it's retain count was decremented.
Further, by assigning your pointer to nil before you released the object, I also would suspect that you will have created a memory leak because the attempt to call release in the dealloc of the controller will not actually release the object.
I'm not 100% sure about this, but ... here is also a link to the Memory Management Programming Guide.
Also, for the future, if you want to be sure, you could run your application using the Leaks performance tool, it should show you where you're leaking memory and what objects are currently allocated in memory, etc...
I could try to setup the scenario in a test project real quick and monitor it using Leaks and update my answer later also.

Testing if an object has been deallocated

I have a situation where occasionally my -tableView: numberOfRowsInSection: method asks for the count of a deallocated NSArray. I'd like to be able to test for this array being deallocated in a way that's safe and doesn't make a call to a zombie.
My code currently looks like:
-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
if (! self.offers){
return 0;
}
return [self.offers count];
}
I just debugger-stepped through this and observed it passing the ! self.offers test and then crashing brutally on [self.offers count]. I have NSZombies turned on, and at that line I get the NSLog message:
-[__NSArrayM count]: message sent to deallocated instance 0x283dc0
So whatever self.offers is, at this point, is not nil, but is also not pointed at anything valid. How do I test for that?
EDIT: Thanks for the tough-love, friends. I've figured out why I've been having trouble with my memory management--it's actually been an issue of delegate relationships lingering longer than they were useful. See here for the full answer to my problem:
Managing calls to objects that get deallocated when the view is backed out of
It's not possible to "test" for this-- once an object is deallocated, it's gone, and the pointer to it is effectively garbage. Doing anything with it is liable to crash.
Sorry to be the bearer of bad news, but the only way to get this to work right is to make sure the memory management around (in this case) offers is correct at all uses-- retain and release correctly at all the points where that instance variable is manipulated, and it will never be non-nil garbage.
You should try running the static analyzer (Build->Build and Analyze) to start with-- this tool can help flag memory management pattern issues without a lot of extra digging on your part.
You should avoid the problem by fixing the code so it does not deallocate the array when you obviously still need it.
You can add
-(void)dealloc { ... }
And leave it empty if it's the right to do, and add breakpoint in it.
This answer correct to ARC and NON-ARC
This might not be relevant to your question (testing if it is deallocated) - but it seems like your offers array has the same or longer lifetime than your UITableViewController, are you certain you are retaining this array or that you aren't accidentally releasing it somewhere else.
I concur with what quixoto has said above.
Another thing you have to ask yourself is, is my application designed correctly? A tableview relies on a datasource to populate it (which in your case is the offers array), so if you're deallocating it somewhere in the code then you need to step back and rethink your design.
If you're testing for whether it's deallocated because you're trying to 'fix' it from a previous problem, then it might be worth looking into your code to see where it is being retained/released.
Yes, once an object is deallocated, it's gone, and the pointer to it is effectively garbage. Doing anything with it is liable to crash.
However it is POSSIBLE to test. There is a workaround for it. (Although workarounds are not a substitute for good design practices!):
You have a global BOOL variable, which you set on the alloc. Here's an example of use for checking whether a AVAudioPlayer isPlaying. If it was playing, and the view was closed, the app would crash. Simply stopping the music was not an option due to background threads, etc. But calling [newPlayer isPlaying] crashes when newPlayer is already released! So a BOOL flag workaround made it work. (Any good design practice comments on this would be valuable.)
// In implementation
static AVAudioPlayer *newPlayer;
static BOOL hasMusicFinishedPlaying;
// When Playing the music, set flag
newPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: soundPath] error:nil];
hasMusicFinishedPlaying = NO;
// Callback method to release new player in playKeySound
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)newPlayer successfully:(BOOL)flag {
[newPlayer release];
hasMusicFinishedPlaying = YES;
}
// On going back to another page. We don't want to keep ViewController in stack.
if (!hasMusicFinishedPlaying){
return;
}
[self.navigationController popViewControllerAnimated:YES];

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: