How to solve this memory leak (iPhone)? - objective-c

How to release this variable with no EXC_BAB_ACCESS ?
//First line create memory leak
UIImage *ImageAvatar = [[UIImage alloc] initWithData:[myg.imageData copy]];
Moins1 = ImageAvatar;
//[ImageAvatar release]; if i release-> EXC_BAD_ACCESS
Moins1 is a menber of the interface is declared like this :
UIImage *Moins1;
...
#property (nonatomic, retain) UIImage *Moins1;

It looks like the problem isn't the UIImage, but rather the NSData. In Cocoa, any copy (or mutableCopy) method returns an object with a +1 retain count, meaning that you own it and are therefore responsible for releasing it.
In your code, you're calling -copy on myg.imageData, but never releasing it. That's a classic example of a memory leak. Here's what I would do to fix it, plus with changing your syntax a bit:
ivar:
UIImage *Moins1;
#property (nonatomic, retain) UIImage *Moins1;
implementation:
NSData * imageData = [myg.imageData copy];
UIImage * ImageAvatar = [[UIImage alloc] initWithData:imageData];
[imageData release];
[self setMoins1:ImageAvatar];
[ImageAvatar release];

You should not need to send -copy to the NSData object. UIImage does not keep a reference to the data around, it just reads it and produces an image. Sending -copy without -release is a memory leak.
However, that does not explain the EXC_BAD_ACCESS. Something else is going on, and not from the code you've posted.

There are two problems in your code. The copying of imageData as indicated by the other contributers, and the assignment to Moins1 field without retaining the object.
The assingment to Moins1 access the field directly, so you would need to do your own retaining. If you don't retain it and release it in the next line, then any subsequence access to the field results into a protection error.
You can use the property for assignment:
UIImage *ImageAvatar =
[[UIImage alloc] initWithData:[[myg.imageData copy] autorelease]];
self.Moins1 = ImageAvatar;
[ImageAvatar release];
Or you can also just do it in one line:
self.Moins1 = [UIImage imageWithData:[[myg.imageData copy] autorelease]];

-(void )dealloc
{
if(self.Moins1!=nil)
{
self.Moins1 = nil;
}
}
see when u give and object a retain property its count is already 1 and when u allocate it its count becomes 2 so when the dealloc is called it will check if its nil and if its not nil make it nil .In this way it will give the retain count of the variable to 0

Related

Why does my NSArray get deallocated?

I'm trying to understand Automatic Reference Counting, as I come from a high-level programming language (Python) and I'm working on a project which use this feature of Objective-C. I often get problems with ARC deallocating objects which I need later, but now I got a concrete example for which I hope I'll get an explanation.
- (void) animateGun:(UIImageView *)gun withFilmStrip:(UIImage *)filmstrip{
NSMutableArray *frames = [[NSMutableArray alloc] init];
NSInteger framesno = filmstrip.size.width / gun_width;
for (int x=0; x<framesno; x++){
CGImageRef cFrame = CGImageCreateWithImageInRect(filmstrip.CGImage, CGRectMake(x * gun_width, 0, gun_width, gun_height));
[frames addObject:[UIImage imageWithCGImage:cFrame]];
CGImageRelease(cFrame);
}
gun.image = [frames objectAtIndex:0];
gun.animationImages = frames;
gun.animationDuration = .8;
gun.animationRepeatCount = 1;
[gun startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:leftGun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
}
The idea behind this snippet of code is simple: I have a (UIImageView*)gun which I animate with the images stored in (NSMutableArray *)frames, at random times. (UIImage *)filmstrip is just an image which contains all the frames which will be used on animation. The first iteration of animation works, but the problems appears on the second iteration, where I get -[UIImage _isResizable]: message sent to deallocated instance ... or -[UIImage _contentStretchInPixels]: message sent to deallocated instance ... or -[NSArrayI release]: message sent to deallocated instance .... This happens at
gun.animationImages = frames;
but I don't understand why. I'm not requesting a fix for my issue, but just to help me understand what's happening here. Thanks.
ARC is a mechanism that removes the need to manually retain/release objects. Here's a nice site that explains how this works: http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
Try changing "leftGun" for "gun". I think that's probably the one that gets deallocated at some point, if you're using it through an ivar. Otherwise, leftGun simply isn't in the scope.
Here's what it should look like:
In your .h file:
#property (nonatomic, strong) IBOutlet UIImageView *leftGun;
In your .m file:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:gun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
Also, not quite sure where "gunShoot" is coming from. Is that supposed to be an enum?
EDIT
Added an example of how the leftGun property should be defined. The reason behind using a property over an ivar is for memory management purposes. If you want to release or destroy an object that is a property, simply set it to nil and the property will take care of releasing the object if it has to.
You may prevent the deallocation of the frames array if you mark it as __block.
__block NSMutableArray *frames = [NSMutableArray array];
see “The __block Storage Type.”

Regarding memory management in Objective C

According to the static analyzer if we have the following property:
#property (retain, nonatomic) SomeObject * object;
and then we assign the property like so:
self.object = [SomeObject alloc] init];
a leak occurs. This makes sense because the alloc init adds +1 to the retain count and then the retaining property also increments the retain count. What is the best solution here? typically I just add an autorelease like so:
self.object = [[SomeObject alloc] init] autorelease];
But sometimes this creates problems for me and I end up over releasing the object causing my app to crash. I don't have any specific examples right now but I remember I had to take out some autoreleases cause of the application crashing. Is there something I am missing here?
EDIT: I have a concrete example now of the issue I was running into.
NSMutableArray *newData = [NSMutableArray array];
//If this is true then we are showing all of the items in that level of hierarchy and do not need to show the summary button.
if (!(contextID.count >= 1 && [[contextID objectAtIndex:contextID.count - 1] isEqual:[NSNull null]]) && contextID.count != 0)
{
GeographyPickerItem * firstItem = [[GeographyPickerItem alloc] init];
firstItem.primaryString = [NSString stringWithString:#"Summary"];
firstItem.subString = [NSString stringWithString:#""];
firstItem.isSummaryItem = YES;
[newData addObject:firstItem];
[firstItem release]; //TODO: Figure out why this is causing EXC_BAD_ACCESS errors
}
self.hierData = newData;
The code above is in the init method of a viewcontroller. HierData is a retained property, which is released in the viewControllers dealloc method. GeographyPickerItem retains the two strings, primaryString and subString and releases them in its own dealloc method. My application crashes (sometimes) when the viewControllers are de-alloced following a pop off of a navigation controller. It crashes with a EXC_BAD_ACCESS signal in the dealloc method of GeographyPickerItem (either on [substring release] or [primaryString release]).
I don't understand why this is happening because I believe I am following proper memory management guidelines. If I comment out firstItem release everything is fine.
The autorelease method you mention is fine, as is the other common idiom of:
SomeObject *thing = [[SomeObject alloc] init];
self.object = thing;
[thing release];
If you end up overreleasing later on, that is your problem. This part, which you're apparently doing correctly, is not the problem.
SomeObject * new_object = [SomeObject alloc] init];
self.object = new_object;
[new_object release];
or use ARC
check the GeographyPickerItem, if the strings properties are assign (and change to retain), or check if you always initialize them (before release).
also remember the difference of manually allocating :
[[NSString alloc] initWith...]
You must release or autorelease.
[NSString stringWith...]
No need to release.
or use ARC like meggar said
Turns out the issue was simple, my dealloc method called super dealloc at the start of the method rather than at the end. You always have to release your instance variables before you call [super dealloc]!

NSLog statement does not print my object

If i add an object to a property "dreamsArr", which is NSMutableArray:
#synthesize dreamsArr;
-(void) viewDidLoad
{
Dream *d1 = [[Dream alloc] init];
d1.title = [[NSString alloc] initWithString:#"my 1st dream"];
self.dreamsArr = [[NSMutableArray alloc] init];
[self.dreamsArr addObject:d1];
Dream *dr = [self.dreamsArr objectAtIndex:0];
NSString *title=dr.title;
const char *chTitle = [title UTF8String];
NSLog(#"%s", chTitle);
}
Why does NSLog print "null"?
when i trace this code, after [self.dreamsArr addObject:d1] , dreamsArr still empty, why?
Because you're using char array placeholder (%s) in NSLog statement instead of object's which should be used to print NSString. Try this:
NSLog("%#", chTitle);
Also, unless you're using ARC, you have a leak on 2nd and 4th lines of viewDidLoad method.
The line below has a leak
d1.title = [[NSString alloc] initWithString:#"my 1st dream"];
The leak comes from the assignment of title property which (i presume) is #property with retain modifier. The alloc calls creates an object with +1 retain count while assignment makes it +2. Since you don't balance it out with release call below in the method - you get a leak. Same goes for the 4th line:
self.dreamsArr = [[NSMutableArray alloc] init];
which creates leak in the very same manner.
Leaks are valid only if you're not releasing your dreamsArr instance variable in viewDidUnload method and title instance variable in the dealloc method of your Dream class.
problem was in the other part of code

"Incorrect decrement" and "Potential leak" messages from Analyzer

When I compile with the analyzer, I get a couple of messages. I have these properties declared:
#property (nonatomic, retain) SyncServicePrimary *syncAndCartOne;
#property (nonatomic, retain) SyncServiceSecondary *syncAndCartTwo;
This method is called from applicationDidBecomeActive and I get "Potential leak of an object allocated".
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
self.syncAndCartOne = [[SyncServicePrimary alloc] init];
self.syncAndCartTwo = [[SyncServiceSecondary alloc] init];
}
This is called in applicationWillResignActive; here I get "Incorrect decrement of the reference count of an object".
-(void) removeTheCartObjects{
[self.syncAndCartOne release];
self.syncAndCartOne = Nil;
[self.syncAndCartTwo release];
self.syncAndCartTwo = Nil;
}
If I set the objects to autorelease, the error goes away, but I want the objects to be released when the app hides itself.
Is this something I am doing right but that is split too far for the analyzer to see the start and end, or is this something I can do better/properly so it won't complain?
Its more than likely that I am missing a simple concept with regard to release and alloc cycles (I've come from PHP and C#).
Your problem is here:
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
self.syncAndCartOne = [[SyncServicePrimary alloc] init];
self.syncAndCartTwo = [[SyncServiceSecondary alloc] init];
}
You're creating the objects and then retaining them (because of the property declaration), so they have a reference count of 2, when only one object is referencing them.
You should do it like this:
-(void)makeTheCartObjectsForCountry:(NSString*)country_key{
SyncServicePrimary *primary = [[SyncServicePrimary alloc] init];
self.syncAndCartOne = primary;
[primary release];
SyncServiceSecondary *secondary = [[SyncServiceSecondary alloc] init];
self.syncAndCartTwo = secondary;
[secondary release];
}
You have defined the properties with attribute retain, so the analyzer assumes that the setter method for the property looks like this:
- (void)setSyncAndCartOne:(SyncServicePrimary *)newValue
{
[newValue retain];
[self->_syncAndCartOne release]; // access the instance variable holding the property value
self->_syncAndCartOne = newValue;
}
If you use #synthesize, the setter method will look like that.
So, when makeTheCartObjectsForCountry: returns, the object in syncAndCartOne has a retain count of 2, but should only have a retain count of 1. That's why using autorelease fixes it.
You shouldn't be doing [self.syncAndCartOne release] for the same reason. The setter method will send the old object a release when you assign nil to the property.

objective c memory leak with array?

In my application i declare an array property,
#property (nonatomic, retain) NSArray *listOfItems;
and in my viewDidLoad method,
listOfItems = [[NSArray alloc] initWithObjects:#"First", #"Second", nil];
I do not release the array in my viewDidLoad, because the objects in the array will be required elsewhere in the application.
Finally in my dealloc method i put,
[listOfItems release];
My question is: Is there a memory leak in this code? The retain count should be increased twice due to the (retain) in the property as well as the alloc in the viewDidLoad, but only decreased once in the dealloc method.
the retain will only 'kick in' when you do it like this
self.listOfItems = [[NSArray alloc] initWithObjects:...];
Now, the retain count is indeed 2. If you leave self out, it will just be one. There is a distinct difference in calling 'set' and just assigning.
To answer your original question; your code is not leaking.
Since your setter retains the array, you must release it, after you allocated and set it in your viewDidLoad method (with this notation I suggest "autorelease").
But perhaps it's easier for you, if you use [NSArray arrayWitObjects:].
NSArray *array=[[NSArray alloc] initWithObjects:#"First",#"Second",nil];
self.listOfItems=array;
[array release];
You, can use this way also.
Just like #MiRAGe said,
listOfItems = [[NSArray alloc] initWithObjects:#"First", #"Second", nil];
The retain count will be 1
but if the code is
self.listOfItems = [[NSArray alloc] initWithObjects:#"First", #"Second", nil];
The retain count will be 2
Yes, there's a potential leak. Consider:
In -viewDidLoad, you set up listOfItems as you've described.
Subsequently, some other code calls yourObject.listOfItems = someNewList;.
Your -dealloc releases listOfItems.
I realize that #2 above probably doesn't happen in your code, but a month from now you may decide that you need to update the list for some reason and introduce this problem. Think about what happens if #2 ever does occur...
Your listOfItems ivar suddenly points
to a different list.
You no longer have a reference to the old list, so it can never be released. That's your leak.
It's much better to release the array in -viewDidLoad after you've assigned it to your property.
It wont be confusing if you practice like this
#property (nonatomic, retain) NSArray *listOfItems;
NSArray *temparray = [[NSArray alloc] initWithObjects:#"First", #"Second", nil];
self.listOfItems = temparray;
[temparray release];
and in dealloc
[listOfItems release];