I am new to objective c and I don't understand how there is a memory leak here:
MessageCustomCell *cell = [[MessageCustomCell alloc] initAutoreleaseWithLine:currentLine AndId:message.UID];
[[cell dateTime] setText:[formatter stringFromDate:message.Date]];
[[cell from] setText:message.From];
[[cell play] setTitle:#">" forState:UIControlStateNormal];
[formatter release];
return cell;
On the return cell; line the analyzer says that there is a "potential leak of an object allocated on line 207 and stored into cell." This is the line where cell is allocated but I'm returning cell so how is this a leak?
Thanks in advance for the help!
The issue, based on the name, is you are trying to return an auto released object in an init function. The static analyzer makes assumptions that instance methods beginning with init return ownership to the caller (increased retain count) even if you call it initAutorelease. The same goes for methods that begin with new. You will continue to get analyzer warnings until you change the name but what you are trying to do needs to be a convenience method of the class.
//Signature
+(id)cellWithLine:(int)line andId:(NSString*)mid;
//Sample Call
[MessageCustomCell cellWithLine:currentLine andId:message.UID];
return [cell autorelease];
Also, you are releasing formatter.
Before Fixing potential leaks we need to know what is retain and release. Retain is allocating memory, Release is deallocating memory.
NSstring *str = [[NSstring alloc] init];
Here we are allocating memory to 'str' variable. In the same .m file we need release the memory for the variable after completing the functionality of it.
Simple write in the code [str release];
It won't cause any memory leaks.
Unless your method name begins with "new" (as in newMessageCell), "alloc" or contains "copy", the returned object is expected to be an autoreleased object. Your code returns the object with a reference count of 1 and a well-behaved caller will not decrement it beyond that. If the caller wishes to retain the cell to take ownership of it, it will do so.
To fix this leak, simply autorelease the cell.
Related
I encounter memory leak with stringWithCString, can anybody find the memory leak in stringWithCstring function?
SomeView *detailViewController = [[SomeView alloc] initWithNibName:#"SomeView" bundle:nil];
detailViewController.test = [NSString stringWithCString:"abc" encoding:UTF8_ENCODING];
the property in SomeView for test variable is
#property (nonatomic,copy) NSString* test;
Is my property declared correctly?
Are you releasing the string in your [SomeView dealloc] method like this:
- (void)dealloc
{
self.test = nil;
[super dealloc];
}
Whatever you use to "detect" the leak, how reliable is that?
Now I've never used properties, but the code above looks pretty correct -- the string should get released. The "stringWithCString:" will autorelease the string anyway, so there's no problem. However, the "copy" in your property seems to indicate that it makes a copy (huh? Surprise!) of the string, and even if I assume that object-type properties are released when the owning object dies -- if the owning object never dies then the copied string will never be released.
Maybe the memory leak detector really meant to say that the copy of that string is never released because you forgot to release the "detailViewController"? That copy would still be in the same source code line, so even if the memory leak detector can give an accurate location but only provides a line number you could be misled...
XCode is reporting a memory leak on a specific line of code:
(NSArray*)myFunction{
NSMutableArray * tempMapListings=[[NSMutableArray alloc] init]; //Xcode says leak is here
//do a bunch of stuff to insert objects into this mutable array
return tempMapListings;
[tempMapListings release]; // but I release it ?!
}
Is this due to releasing as an NSArray an mutable array? Since mutable inherits from inmutable, I wouldn't think this is a problem, and in any case, the object is released anyway. I'd appreciate the advice of a second eye.
No you're not releasing it. The return statement really ends the execution of the method at that point. So, the line below it, in your case
[tempMapListings release]; // but I release it ?!
is not executed.
Instead, you use autorelease:
-(NSArray*)myFunction{
NSMutableArray * tempMapListings=[[NSMutableArray alloc] init];
//do a bunch of stuff to insert objects into this mutable array
return [tempMapListings autorelease];
}
You can learn about autorelease in many places. Look for it in Apple's own documentation; you can also google it.
You're releasing tempMapListings after your return from the function. After a return statement, no more code is executed on that branch. Ergo, your [tempListListings release] statement is never run. Moreover, as you're returning it, you don't actually want to release it straight away - the caller will never have a chance to retain the array!
Autorelease pools are your friend here. Objects added to an autorelease pool are released on your behalf "eventually", giving your caller time to grab the result. To add your object to the default pool, change your allocation line to
NSMutableArray *tempMapListings = [[[NSMutableArray alloc] init] autorelease];
and remove that last release call.
For more information on autorelease pools, have a read of Apple's documentation. They're really quite useful.
I am trying to get the hang of retain / release. I get that they are a matched set. But I don't know when I have to retain references.
-(void)sampleMethod:(RandomClass *) obj {
[obj retain];
// Do stuff to object...
[obj release];
}
Is it necessary to retain (and thus release) obj?
I am worried about obj going away. Does it follow that you must (if) retain reference parameters as soon as possible in the function? What about the space of time between the functions call and the first instruction of the function?
Thanks!
Short answer; use ARC.
Joe's answer is more or less correct. Until it isn't.
In general, there is no need to retain arguments or return values from other methods. However, the resulting code only works by coincidence and convention, not by algorithmic analysis.
Consider:
NSString *foo = [aMutableArray objectAtIndex: 5];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
BOOM!
Your code just crashed. Maybe (it won't crash if foo happens to be a constant string or happens to have been retained by something else or happens to have been retain/autoreleased somewhere else).
Technically, that should be:
NSString *foo = [aMutableArray objectAtIndex: 5];
[foo retain];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
[foo release];
That is, foo should be retained the moment it comes into scope and released the moment it is no longer used in a scope. Or you could [[foo retain] autorelease];, but autorelease pressure can be a problem (it generally isn't, but it can be).
ARC does this kind of analysis and would ensure that foo is retained as shown above when necessary.
You do not have to worry about the object being passed going away so there is no need to retain it. Proper memory management* ensures that the object will live for the duration of your method because it will be within the same thread as the caller, therefore the autorelease pool for that thread should not be drained and the caller can not release the object until your method has returned. This even holds true with methods such as performSelectorInBackground because that will retain the argument.
*Proper memory management - This means each thread that uses auto released objects gets it own autorelease pool that is drained within the same context it is created and objects passed across threads are properly retained.
I am facing some strange memory leak in our existing iPad application,
Here is a function which gives memory leak in instrument
-(NSString *)retriveInfo:(NSString*)fromstring:(NSString*)searchstring
{
NSArray *arrRetrive = [fromstring componentsSeparatedByString:searchstring];
if([arrRetrive count]!=0){
if ([arrRetrive count]!=1){
NSString *strDisplayOrder = [arrRetrive objectAtIndex:1];
arrRetrive = [strDisplayOrder componentsSeparatedByString:#"<"]; //MEMORY LEAK
}
}
return [arrRetrive objectAtIndex:0];
}
Here is a input parameter
Param 1 : <displayorder>1</displayorder><filename>201103153_0100.pdf</filename><title>【1面】東日本巨大地震直撃、日経平均一時675円安[br]原発関連売られる、東電はS安</title><category>トップ・注目株</category><dirpath>/var/www/mssite/webapp/data/pdf/20110315</dirpath><TimeStamp>201103141700</TimeStamp><FirstPageImg>20110315top.png</FirstPageImg></pagedata>
Param 2: <displayorder>
Basically i want to found (parse) value between start and end tag.
(I know NSXMLParser class but asper i explain this one is existing code and if i changed in code its too much time consuming)
Any suggetion?
With Regards
Pankaj Gadhiya
The code you've posted doesn't look like it's leaking memory -- all the methods you're calling are of the autorelease type (i.e. there's no new, alloc, copy, or retain in the code).
It's probably the code you have that calls retrieveInfo and does something with the result that's leaking memory (e.g. overretaining it). The leaks tool is pointing you at the componentsSeparatedByString because that's where the memory was allocated which was eventually involved in a memory leak.
Can you show us how you call retrieveInfo and what you do with the result?
Btw, what's the point of this nested if?
if([arrRetrive count]!=0){
if ([arrRetrive count]!=1)
It's wasteful, you might as well write this and get the same effect:
if ([arrRetrive count] > 1)
That leak probably means that you're over-retaining the return value. And leaks-tool just shows you the place where it was created.
You are leaking the NSArray when you re-assign a new NSArray inside the if block. The pointer to the original array is lost, which means that the runloop cannot release the memory allocated for the first result. The memory allocated for the second result is released.
You should really use a proper parser... however to address the leak, the following will work.
-(NSString *)retriveInfo:(NSString*)fromstring:(NSString*)searchstring
{
NSArray *arrRetrive = [fromstring componentsSeparatedByString:searchstring];
NSString *result = nil;
if([arrRetrive count]!=0){
if ([arrRetrive count]!=1){
NSString *strDisplayOrder = [arrRetrive objectAtIndex:1];
result = (NSString *)[[strDisplayOrder componentsSeparatedByString:#"<"] objectAtIndex:0];
}
}
return result;
}
What do you do with the object that's returned by this method? [arrRetrive objectAtIndex:0] is likely what's being leaked.
Leaks indicates that line with componentsSeparatedByString: because that's where the strings in the array are allocated. But the array isn't leaked.
Go into Leaks, look at a leaked instance, and click that little arrow button. You'll see all the retains and releases of the leaked object, which should point you to the problem.
I'm using the iPhone SDK 3.0, but I think this is a general misunderstanding of how things work w/ c & memory management.
I've overridden the viewWillAppear method like this
#implementation MyViewController
- (void)viewWillAppear:(BOOL)animated {
NSArray *items = [NSArray arrayWithOjbects:self.searchButton, self.trashCan, nil];
[self.bottomBar setItems:items animated:YES];
}
// other stuff...
#end
when I try to switch away from the view controller above and switch back everything works properly.
BUT, my inclination is to "release" the original pointer to "items" because I think a reference to the NSArray is now held by bottomBar.
But when I do this (see code below) and try to switch away from the UIViewController, I get a memory management error (-[CFArray count]: message sent to deallocated instance 0xd5f530).
- (void)viewWillAppear:(BOOL)animated {
NSArray *items = [NSArray arrayWithOjbects:self.searchButton, self.trashCan, nil];
[self.bottomBar setItems:items animated:YES];
[items release];
}
Do I need to not release items in this case? Or am I doing something wrong?
Obviously, the empirical evidence indicates that I shouldn't release "items", but it's not clear to me why this is the case.
Thanks for any info/"pointers"!
You do not need to release it because you never init'd it. [NSArray arrayWithObjects:...] returns an autoreleased object. You are not responsible to release it, because it has had the autorelease message sent to it when it returned from the method. You only have to release what you init! (If you had used [[NSArray alloc] initWithObjects:...] you would have had to.)
When you call arrayWithObjects: on NSArray:
NSArray *items = [NSArray arrayWithObjects:self.searchButton, self.trashCan, nil];
You are returned an autoreleased array. The array is returned to you autoreleased, because you do not call alloc, new, or a method containing copy on it. This signifies that you do not need to memory manage that object. (Take a look at the Memory Management Programming Guide for Cocoa for more information)
However, it is then retained when you call setItems on self.bottomBar, passing the array as an argument, bumping its retain count up to 1, but then you release it, returning its retain count back to zero, which causes it to be deallocated.
Since the array is retained by self.bottomBar, this implies that it is managing the memory of the array. When it is no longer needed, the array will be released, implying that the class no longer needs the array, which is the correct way to manage the memory.
For heavens sake guys, just point people to the Memory Management Rules. Don't paraphrase them. Don't say "returns an autoreleased object" (which is not necessarily true, and is irrelevent even when it is true). Just point them to the rules.
The rules are a sum total of 9 paragraphs! There is no need to paraphrase them, abrieviate them, or restate them. They are clear and concise and explicit.
Read the rules, follow the rules, and you will have no memory management problems.
Here's the short version:
+[NSArray arrayWithObjects:] returns an object that you do not own, so no, you should not release it.
On the other hand, if you had done:
NSArray *items = [[NSArray alloc] initWithObjects:self.searchButton, self.trashCan, nil];
this creates an object with a retain count of 1, so you would need to release it to prevent it from leaking.
Check out the Memory Management Programming Guide for Cocoa for more details.