When to release. Instruments says I have a leak - objective-c

Sometimes I wonder where I would be able to get great information other than from the stack overflow community. I suppose the Objective-C memory management handbook wouldn't be bad, but I feel like you guys can tell me why as opposed to just what to do.
I have the following code:
NSString* rawTickerData = [[NSString alloc] initWithData: op.requestData encoding:NSUTF8StringEncoding];
NSArray* lines = [rawTickerData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for(NSString* line in lines)
{
NSArray* fields = [line componentsSeparatedByString:#","];
if([fields count] > 1)
{
[self.tickerData addObject:fields];
}
}
[rawTickerData release]
Instruments tells me that fields is leaking, but trying to release it after the if statement or doing an autorelease gives an EXC_BAD_ACCESS.
The same thing happens for lines. Releasing it anywhere or trying to do autorelease gives EXC_BAD_ACCESS or "trying to double free" (for autorelease).
Yet, instruments is still saying that these are leaking. Am I missing something?

Unless I'm missing something, the code you've posted is correct. fields is an autoreleased object that gets retained when added to self.tickerData. lines is also autoreleased, so it isn't leaking (at least not in the code shown).
If you're leaking anywhere, it's because you're not properly cleaning up self.tickerData. If you comment out the [self.tickerData addObject:fields]; line, are you still getting leaks reported? If not, make sure you're calling [tickerData release] (or something similar, like self.tickerData = nil) somewhere, probably in your dealloc implementation.

In these cases the best practice is to release your object's at the end of each loop, if you retained them. In this case your fields variable gets an autorelease object, the best option is to use an NSAutoReleasePool to release your objects at the end of the loop.
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString* rawTickerData = [[NSString alloc] initWithData: op.requestData encoding:NSUTF8StringEncoding];
NSArray* lines = [rawTickerData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for(NSString* line in lines)
{
NSArray* fields = [line componentsSeparatedByString:#","];
if([fields count] > 1)
{
[self.tickerData addObject:fields];
}
[pool drain];
}
[rawTickerData release];
This will flushes all the autoreleased objects if they are don't needed. If you dont use autorelease pool, your objects are living until your method terminates.
If this doesn't resolve your leak problem i suggest to initialize your array like this:
NSArray *lines = [[NSArray alloc]initWithArray:[line componentsSeparatedByString:#","]];
//and release at the end of the loop
[lines release];

Related

NSString copy or alloc? Do you feel lucky?

I have a thread that needs information from the GUI before starting. What I mistakenly tried to do at first was create pointers to the NSTextFields like so:
NSString *info = [gui_field stringValue];
//launch thread
[self performSelectorInBackground:#selector(myMethod:) withObject:info];
This caused problems when I tried to manipulate "info" from within the thread. I assume this is the case because technically, it was still pointing to the string representation of the NSTextField outside the thread.
This fixed the problem:
NSString *info = [[gui_field stringValue] copy];
I assume this made a copy (with its own memory space) that did not rely on the NSTextField at all. I also assume this should be thread-safe.
Is this the appropriate way to do this? I suppose I could have done this:
NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];
Are the two producing the same result? And do I have to explicitly call release on the string when using "copy" or is it autoreleased by default?
Update: or, perhaps I could just send a pointer to the thread, and copy the string with "autorelease," adding it to the thread's autorelease pool:
NSString *info = [gui_field stringValue];
//launch thread
[self performSelectorInBackground:#selector(myMethod:) withObject:info];
-(void)myMethod:(NSString*)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *copied_str = [[info copy] autorelease];
//do stuff
[pool drain];
//copied_str should now be history
}
This way, I don't have to worry about explicitly releasing copied_str. It will be gone once the thread ends.
No need to rely on luck :)
alloc, copy, new and mutableCopy mean you own the object. Both of those will give you a retained object. If you're managing memory, you need to release it.
By convention, other methods will give you an autoreleased object.
As an example, if you want an autoreleased object, you can call:
NSString *str = [NSString stringWithString:yourString];
See the memory management guide:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
Specifically the four rules here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
Finally, both will copy the string.
from the NSString docs:
initWithString:
Returns an NSString object initialized by copying the characters from another given string.
copy is from NSObject. It defines copy as:
Return Value
The object returned by the NSCopying protocol method copyWithZone:, where the zone is nil.
NSString implements the NSCopying protocol so copy will return a copy of the string.
There is one exception where the string isn't copied by initWithString - if you pass a string literal it will wrap the pointer to the constant and ignore retain/release. See here if you're curious: Difference between NSString literals
NSString *info = [[gui_field stringValue] copy];
NSString *info = [[NSString alloc] initWithString:[gui_field stringValue]];
Those do pretty much the exact same thing.
[self performSelectorInBackground:#selector(myMethod:) withObject:info];
-(void)myMethod:(NSString*)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *copied_str = [[info copy] autorelease];
No, you can't do that. Even accessing the GUI string object just to copy it could be enough for a crash.
I think this is a case where the usually recommended patterns for memory management really don't provide a great solution, so you can go outside them.
NSString *info = [[gui_field stringValue] copy];
//launch thread
//pass ownership to callee
[self performSelectorInBackground:#selector(myMethod:) withObject:info];
// myMethod owns info!
-(void)myMethod:(NSString*)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[info autorelease];
Another option is retain infoCopy as an instance variable somewhere. That would let you use normal memory management patterns, but it doesn't fit semantically. It's really not an instance variable, it's an argument.
"I asked for an argument."
"This is abuse."

Is this a correct situation to call release on an object in Objective-C?

I'm new to Objective-C and I am having some difficulty with understanding memory management.
So let's say I have a class and an instance variable of type NSString* that isn't tied to a property. Would this situation leak memory?
myString = [[NSString alloc] init];
//more program stuff
myString = [[NSString alloc] init];
Should I have called [myString release] before I set myString equal to a new object? Will this sort of code leak memory? Do I have to release an object like this every time I have the pointer point to a different object?
First, Apple's Memory Management Programming Guide is a great place to look for examples and instructions about memory management.
Now to your question. When you call myString = [[NSString alloc] init]; you are reassigning the pointer myString and as such lose access to the original NSString, thus creating a memory leak.
The general rule of thumb here is that for every alloc you should have a release and these must alternate appropriately. If you do
myString = [[NSString alloc] init];
// ...
myString = [[NSString alloc] init];
// ...
[myString release];
[myString release];
you are releasing the same instance twice which results in overreleasing and an error BAD-ACCESS. The correct thing to do is
myString = [[NSString alloc] init];
// ...
[myString release];
myString = [[NSString alloc] init];
// ...
[myString release];
so that each instance is correctly released.
For future, stick to the simple rule that for every alloc/copy/retain you should pair it with a release.
Yes this will leak.
By allocating and assigning another NSString instance to the same variable myString, you lose reference to the original content of myString and therefore the ability to send it a release message.
Both, the Clang static analyzer and the Leaks instrument should uncover this leak.
Yes, you need to release the first object before you reassign your variable to point to the second object. Otherwise, you lose track of your first object and you leak it because you can't release it. You are responsible for releasing the object because you created it (via alloc) as explained in the Memory Management Rules.
Also, bear in mind that [[NSString alloc] init] is creating an empty and immutable string (NSStrings are immutable meaning that they can not be changed after creation). There is little point in doing this.

Why does my object still work after countless releases?

I can never seem to deallocate my NSMutableString as shown below. The initial retain count should be 1, but after releasing several times, the string is still usable like nothing happened!
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
NSMutableString* s = [[NSString alloc]initWithString:#"AAA"];
[s release];
[s release];
[s release];
[s release];
[s release];
NSLog(#"%#",s);
[pool drain];
return 0;
}
Of course, if I use Analyze it still tells me that I release a released object on the second release.
Scott's answer is the correct general one, but in this particular case, the reason is that NSString literals (i.e. #"") are uniqued compile-time constants and do not actually do anything at all when retained and released. Your assignment of it to an NSMutableString* does not actually make it an NSMutableString, so what you've written is equivalent to
[#"AAA" release];
[#"AAA" release];
[#"AAA" release];
[#"AAA" release];
[#"AAA" release];
[#"AAA" release];
Releasing an object tells the runtime that it can destroy the object, at least as far as you're concerned, but it doesn't require that the object be destroyed immediately: After your first [s release], Cocoa is free to do whatever it pleases with the memory formerly used by s. It might give that memory to the next object that does an alloc, in which case your later attempts to access s will result in a fiery runtime crash… or it might not need that memory right away, in which case you might get away with accessing a released object.
The rule of thumb is less "I've released this object, which means it no longer exists" and more "I've released this object, which means it's no longer guaranteed to exist."

Leak or Crash - difference between autorelease and release

I have a comprehension question. This method is given:
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
result = [result stringByAppendingString:#"something"];
NSArray *arr = [NSArray arrayWithObject:result];
//[result release];
return arr;
}
If I uncomment the release the App would crash and say it cannot access a released object.
By not releaseing the result string Instruments would report a leak (NSPlaceholderString).
I can autorelease it on the same line I alloc it, that would solve the problem (which I'm currently doing in my App).
If I understand it correctly stringByAppendingString: should create an autoreleased object so the 'old' result could be deallocated. Then the method arrayWithObject: should copy the object into an array. So my thought was to release the string after it was copied to the array.
Am I missing something or something wrong with my knowledge?
Let's go through your code line by line.
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
This creates a data object. You don't own it, but it will stick around for the rest of the method's time. So far, so good.
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
This creates a string object that you own. Again, no problem here — we just need to release it later.
result = [result stringByAppendingString:#"something"];
You throw away your reference to the string object that was in result and store a new string object that you do not own. This is a leak because you can no longer release the original string. Also, you're correct in noting that the new string can be treated as an autoreleased object — which means you should not release it.
NSArray *arr = [NSArray arrayWithObject:result];
Contrary to your belief, this does not copy anything. It merely keeps a reference to the new string and retains it.
//[result release];
You should not release result at this point, because the object it contains is not one you own — you got it from stringByAppendingString:, not from a method with new, alloc, retain or copy in its name. Releasing this object that you do not own will almost certainly result in a crash at some point. The old object that you own and should release was lost two lines earlier, and releasing something else in its place won't help.
result = [result stringByAppendingString:#"something"];
This line replaces the first allocated string by a new autoreleased string.
So the first string is leaked and the second one should not be released. This explains why uncommenting the release line crashes.

memory management: am i doing something wrong here?

In a very small number of cases in my iphone app, I get a crash after the for loop in the code below:
ABAddressBookRef addressBookInit = ABAddressBookCreate();
CFMutableArrayRef abContacts =
(CFMutableArrayRef)ABAddressBookCopyArrayOfAllPeople(addressBookInit); // get array of all contacts
CFArraySortValues (abContacts, CFRangeMake(0, CFArrayGetCount(abContacts)), (CFComparatorFunction)ABPersonComparePeopleByName, (void *)ABPersonGetSortOrdering());
NSArray *copypeople = (NSArray *) abContacts;
NSMutableArray *tempTheadlist = [[NSMutableArray alloc] init];
for (int i=0; i < copypeople.count; i++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
ABRecordRef record = [copypeople objectAtIndex:i];
if (blah blah)
[tempThreadList addObject: someObject];
[pool release];
}
// POINT OF CRASH AFTER LOOP ENDS
if (tempTheadlist.count > 0)
[NSThread detachNewThreadSelector: #selector(loading_pictures:) toTarget:self withObject:tempTheadlist];
[tempTheadlist release];
[copypeople release];
CFRelease(addressBookInit);
Any reason why it should crash at any point here?
(1) ABAddressBookCopyArrayOfAllPeople() returns a CFArrayRef, not a CFMutableArrayRef.
(2) All the casts between CFArrayRef, CFMutableArrayRef, and NSArray are irrelevant. NSArray and CFArray are synonymous.
(3) The autorelease pool in the for() loop is irrelevant. There aren't any new objects being created in the for() loop and, thus, nothing to fall in the pool. Nor will objectAtIndex: retain/autorelease the objects.
(4) That you are sorting the array returned by ABAddressBookCopyArrayOfAllPeople() may likely be a crash trigger. That function is declared as returning a CFArrayRef() and it should be treated as immutable.
If the app is crashing, post the backtrace of the crash. Without that, it is hard to tell what is specifically triggering the crash. Is it crashing in the thread that ran the above code? ... or crashing in the newly created thread?