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]!
Related
I'm currently developing an iOS application which was started by another developer.
Usually, I make a property for every instance variable (assign for int, bool etc. / retain for all classes).
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
So I use:
NSString *tmpMyVar = [[NSString alloc] init];
[self setMyVar: tmpMyVar];
[tmpMyVar release];
Or:
NSString *tmpMyVar = [[[NSString alloc] init] autorelease];
[self setMyVar: tmpMyVar];
In this new project, the previous developer didn't use #property/#synthesize so I'm wondering what will be the result of the previous line of code in this context (it doesn't call setter I guess)? Memory Leak?
The previous developer releases variable in dealloc method, just like me.
Thank you very much!
Since it directly assigns the instance variable to the allocated object it's retain count is 1 (because, like you said, a setter isn't called).
And because it's released in dealloc, it's all balanced out. So no memory leaks.
So in my projects, this line causes a leak:
myVar = [[NSString alloc] init]; (alloc/init +1, retain in setter +1, release in dealloc -1 => +1)
No,it wouldn't even in your projects, because, as you pointed out, no setter is used.
Also, when using properties, it is the recommended way to access instance variables directly in the init method, instead of using setters.
To inspect for questionable memory-leaks like your example, also use the clang static analyzer or instrument's leak tool.
You need to look at the other developer's setter implementation. Make sure they release the existing value and retain the new value; something like:
- (void)setMyString:(NSString *)string
{
[string retain];
[_string release]; // ivar
_string = string;
}
The only advantage to implementing your own setter/getter methods is to do something (other than setting the ivar) when a value is set. If the methods don't do anything like this then why not change all implementations to #property/#synthensize?
I am doing my project in xcode 4.2 (Older Version). For my application, I just set the variables, arrays in dto class for using in entire app lifecycle. so I set with a property like this.
AppDTO(sub class of NSObject)
AppDTO.h
#property(nonatomic,retain)anotherAppDTO *aAppDTO;
#property(nonatomic,retain)NSMutableArray *array1;
#property(nonatomic,retain)NSMutableArray *array2;
#property(nonatomic,retain)NSString *string1,*string2,*string3;
AppDTO.m
- (id)init
{
self = [super init];
if (self) {
self.aAppDTO = [[anotherAppDTO alloc]init];
self.array1 = [[NSMutableArray alloc]init];
self.array2 = [[NSMutableArray alloc]init];
self.string1 = #"Hello";
self.string2= #"Hai";
}
}
-(void)dealloc
{
if(array1 != nil)
{
[array1 release];
array1 = nil;
}
if(array2 != nil)
{
[array2 release];
array2 = nil;
}
[aAppDTO release];
aAppDTO = nil;
[super dealloc];
}
when I analyze my app in Xcode 4.3.2, I get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when I change self.array1 to array1, warning goes away.
What is the reason for using self. do I need to use self if I set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
Also in dealloc method, I heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
Do I need to release my string in dealloc method.
Also I am releasing aAppDTO in dealloc method. if I allocate some objects in anotherAppDTO class, will it release automatically when I call [aAppDTO release] method.
Can anyone clarify me.
Many Thanks,
Anish
You get the warning because when you write :
self.array1 = [[NSMutableArray alloc]init];
is the same as :
[self setArray1: [[NSMutableArray alloc]init]];
As you can notice you are not allocating the underlying array1 private variable, but you are calling the setter of the property that since it is declared as retain it retains the object once assigned, this means that when you eventually will assign another object the second time with the setter the first object will remain with a retain count of one until the application will be closed (since you don't have any reference to that object anymore ...) .
Take a look at this great article to understand better Manual Reference Counting in Objective-C .
when i analyze my app in Xcode 4.3.2, i get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when i change self.array1 to array1, warning goes away.
the analyzer's right. the parameter is retained when set. as well, you should favor direct access in initialization and dealloc. so, you should just write array1 = [[NSMutableArray alloc] init];, and be done.
What is the reason for using self. do i need to use self if i set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
those go through the accessor methods. if not in initialization or dealloc, you should favor going through the accessor methods because that is the common correct execution path for a fully constructed object.
Also in dealloc method, i heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
correct.
Do i need to release my string in dealloc method.
yes.
Also I am releasing aAppDTO in dealloc method. if i allocate some objects in anotherAppDTO class, will it release automatically when i call [aAppDTO release] method.
when its reference count reaches 0, its dealloc will be called.
I think the others have answered your question.
I do want to draw your attention to Apple's excellent Advance Memory Management Programming Guide: Practical Memory Management, in which they walk through these sorts of scenarios. It's hard to take it all in on the first reading, but it really does cover this stuff. In answer to your question about the use of instance variables versus the accessor methods, I draw your attention to the section labeled to "Don't Use Accessor Methods in Initializer Methods and dealloc".
I'm programming an iPhone app and I had a question about memory management in one of my methods. I'm still a little new to managing memory manually, so I'm sorry if this question seems elementary.
Below is a method designed to allow a number pad to place buttons in a label based on their tag, this way I don't need to make a method for each button. The method works fine, I'm just wondering if I'm responsible for releasing any of the variables I make in the function.
The application crashes if I try to release any of the variables, so I'm a little confused about my responsibility regarding memory.
Here's the method:
FYI the variable firstValue is my label, it's the only variable not declared in the method.
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
NSString *addThisNumber = [[NSString alloc] init];
int i = placeHolderButton.tag;
addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *newLabelText = [[NSString alloc] init];
newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
//[placeHolderButton release];
//[placeHolderString release];
//[addThisNumber release];
//[newLabelText release];
}
The application works fine with those last four lines commented out, but it seems to me like I should be releasing these variables here. If I'm wrong about that I'd welcome a quick explanation about when it's necessary to release variables declared in functions and when it's not. Thanks.
Yes, you need to release them, but you need them just a little longer than beyond the end of your function.
The solution is called autorelease. Just replace release with autorelease and the objects stay around until the program gets back to the runloop.
When the program gets back there, everybody interested in one of the objects should have sent a retain message to it, so the object will not be deallocated when released by the NSAutoreleasePool.
edit actually, looking at your code, there's a lot more wrong with it. E.g. this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
doesn't make sense. First you allocate an object, then assign (a pointer to) it to variable placeHolderButton. That's fine.
Then you assign sender to that same variable. The reference to the object you just created is now lost.
Not sure if I get what you want, but this would be better:
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = sender; // this is still a little useless, but ok
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *placeHolderString = firstValue.text;
NSString *newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
}
No allocs, so no releases necessary. The strings returned by those functions are already added to the autoreleasepool, so they will be deallocated automatically (if needed).
Well. Release them when you are done with them. The sooner the better. Some objects are tricky if you are new to memory management.
Release them in the dealloc method then.
The auto release pool can be handy, some people might disagree according to the performance issues.
you need to release anything containing the word new, alloc/init or copy.
also, you don't need to alloc/init this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
another way of doing this is:
UIButton *placeHolderButton = (UIButton *)sender;
in your version, it is allocating an instance with a retain count of +1, but you are immediately replacing the reference, so there is no way of releasing the memory later.
you are creating a lot of instances with alloc/init, and then replacing their references with autoreleased instances.
you could use
NSString *placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
instead of
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
which is again replacing a manually managed instance created on the first line, with an autoreleased instance on the second.
infact you could replace every alloc/init in this with the factory method and not have to deal with memory at all in it as they would be autoreleased instances.
-(IBAction)inputNumbersFromButtons:(id)sender {
//cast sender as a UIButton to suppress compiler warning, and allow us to reference it as placeholder button
UIButton *placeHolderButton = (UIButton *) sender;
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
[firstValue setText:[firstValue.text stringByAppendingString:addThisNumber]];
}
If you look at the class docs for NSString, any method with a + next to it(ie +stringWithString:(NSString *)string) is a class method, don't use these methods on a reference after you have called alloc/init on it.
I find it puzzling that you use alloc/init on a UIButton.
I always use the factory methods, e.g.
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeCustom];
This returns an autoreleased button which I immediately add to its intended parent view.
Can't confirm it right now, but it looks as if the SDK caches UIButton instances and performs some optimizations behind the scenes. Every time I tried to retain a UIButton ivar, performance has degraded (especially when there is many sub views on screen)
Given the following property definition:
#property (nonatomic,retain) MyObject* foo;
does the following code cause a memory leak:
self.foo = [[MyObject alloc] init];
?
It looks like the alloc call increments the retain count on the object to 1, then the retain inside the property setter increases it to 1. But since the initial count is never decremented to 0, the object will stick around even when self is released. Is that analysis correct?
If so, it looks like I have two alternatives:
self.foo = [[[MyObject alloc] init] autorelease];
which is not recommended on the iPhone for performance reasons, or:
MyObject* x = [[MyObject alloc] init];
self.foo = x
[x release];
which is a bit cumbersome. Are there other alternatives?
Are there any alternatives?
No.
You are not going to be able write much of an iPhone application without using autorelease and the Cocoa Touch library uses them in many places. Understand what it's doing (adding the pointer to a list for removal on the next frame) and avoid using it in tight loops.
You can use class method on MyObject that does alloc/init/autorelease for you to clean it up.
+ (MyObject *)object {
return [[[MyObject alloc] init] autorelease];
}
self.foo = [MyObject object];
The easiest way to manage a retained property on the iPhone is the following (autorelease is not as bad as you think, at least for most uses):
-(id)init {
if (self = [super init]) {
self.someObject = [[[Object alloc] init] autorelease];
}
return self;
}
-(void)dealloc {
[someObject release];
[super dealloc];
}
The autorelease releases the reference to the floating instance which is assigned to self.object which retains its own reference, leaving you with the one reference you need (someObject). Then when the class is destroyed the only remaining reference is released, destroying the object.
As described in another answer, you can also create one or more "constructor" messages to create and autorelease the objects with optional parameters.
+(Object)object;
+(Object)objectWithCount:(int)count;
+(Object)objectFromFile:(NSString *)path;
One could define these as:
// No need to release o if fails because its already autoreleased
+(Object)objectFromFile:(NSString *)path {
Object *o = [[[Object alloc] init] autorelease];
if (![o loadFromFile:path]) {
return nil;
}
return o;
}
You are right, self.foo = [[MyObject alloc] init]; is leaking memory. Both alternatives are correct and can be used. Regarding the autorelease in such a statement: keep in mind that the object will released by the autorelease pool as soon as the current run loop ends, but it will most probably be retained a lot longer by self, so there is no issue with memory usage spikes here.
I have some code that looks like the following:
NSMutableArray *bar = [[NSMutableArray alloc] initWithCapacity:0];
NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0];
[foo setObject:[NSNull null] forKey:#"yay"];
[bar addObject:foo];
[foo release];
Instruments is showing that foo is leaking. I understand why that is happening. Foo's retain count when alloc'd is 1. Then when bar addObject's foo, the retain count goes to 2. Later when I release foo, it goes down back to 1. Still a leak. However, later on in my code, (in a separate method, which is why I think this might be shown as a leak)
[bar removeAllObjects];
Why is foo shown as leaking if I do removeAllObjects later on?
** NOTE **
I didn't include it in my original post, but bar is indeed being released in the classes dealloc method.
I think (and I think you hinted at this possibility as well) that Instruments is marking it as a potential leak, because it hasn't looked ahead far enough to see that bar will be responsible for removing/releasing all its objects in said separate method..
Given what you show, it is bar that never gets released. Calling [bar removeAllObjects] only removes the objects it contains. Instead, you should call [bar release] when you are done with bar. This will automatically release all of the objects that bar holds, plus release the bar object itself.
You state that you understand the memory management concepts, so perhaps you just didn't show bar being released in your example.
edit: I think craig has the right idea in his answer. One way to avoid the warning (maybe) would be to allocate bar in the class init method. I usually find it beneficial to maintain a symmetry between my init and dealloc methods when it comes to member variables, and this would be a good example:
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
bar = [[NSMutableArray alloc] initWithCapacity:0];
return self;
}
- (void)dealloc
{
[bar release];
[super dealloc];
}
- (void)YourMethod
{
NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0];
[foo setObject:[NSNull null] forKey:#"yay"];
[bar addObject:foo];
[foo release];
}
The NSMutableArray should be releasing it when removeAllObjects is called. You shouldn't need to release or add it to an autorelease pool.
From O'Reilly's chapeter on Memory Management:
When you add an object to a collection, it is retained. When you remove an object from a collection, it is released. Releasing a collection object (such as an NSArray) releases all objects stored in it as well.
Perhaps something else is going on in instruments?