Releasing an NSString that I am done with causes a crash - objective-c

Note the commented-out [printvolfirst release]; line below. If I un-comment it, the program crashes. I can't figure out why. The printvolfirst variable is not used anywhere else except in the lines of code you see here. After it is assigned to printvol I'm done with it. So why not release it?
vol = vol / 1000000;
NSNumberFormatter * format = [[NSNumberFormatter alloc] init] ;
[format setPositiveFormat:#"#.#"];
NSString * printvolfirst = [[NSString alloc]init];
printvolfirst = [format stringFromNumber:[NSNumber numberWithFloat:vol]];
NSString * printvol = [[NSString alloc] initWithFormat: #"%#M", printvolfirst];
self.Pop.vol.text = printvol;
[printvol release];
//[printvolfirst release];
[format release];

stringFromNumber: autoreleases the returned object. If you release it again, it's released after it has been deallocated.
In fact, you don't even need this code:
NSString*printvolfirst=[[NSString alloc]init];
You can turn on 'Run Static Analyser' in the build settings to get warned about such things.

You are deallocating an autoreleased string. Although you are doing NSString*printvolfirst=[[NSString alloc]init];, you are losing the reference to that object when you do printvolfirst=[format stringFromNumber:[NSNumber numberWithFloat:vol]]; where you assign an autoreleased object to printvolfirst. In the process, you have also created a memory leak. You don't have to release it.

Related

Releasing or Autoreleasing objects

I have a problem understanding this code:
- (void)subnetMaskByNumberOfSubnetBits:(id)sender{
// ------- Sets the subnet mask when the user selects the number of bits
NSNumberFormatter *stringToNumber = [[NSNumberFormatter alloc] init];//TURN A STRING INTO A NUMBER
NSNumber *selectedAmountOfBits = [[NSNumber alloc] init];//CONTAINS THE SELECTED NUMBER OF BITS
selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
[self changeSubnetMaskUsingNumberOfMaskBits:selectedAmountOfBits];
//RELEASE
[stringToNumber release];
[selectedAmountOfBits release];
}
I kept getting errors because of the fact that I released selectedAmountOfBits.
I initialized the object using alloc and init.
Why don't I need to release it?
The problem is that you are assigning an object to selectedAmountOfBits twice.
NSNumber *selectedAmountOfBits = [[NSNumber alloc] init];
allocates a new NSNumber object that you own and assigns it to selectedAmountOfBits.
selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
assigns a new autoreleased object to selectedAmountOfBits. This means that when you do [selectedAmountOfBits release], you are actually trying to release an object that you do not own. You are also leaking the original NSNumber that you created since you've lost any reference to it.
The solution is to remove the alloc/init line, keep the autoreleased NSNumber, and get rid of the line where you release it. The final code should look like this:
- (void)subnetMaskByNumberOfSubnetBits:(id)sender{
// ------- Sets the subnet mask when the user selects the number of bits
NSNumberFormatter *stringToNumber = [[NSNumberFormatter alloc] init];//TURN A STRING INTO A NUMBER
NSNumber *selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
[self changeSubnetMaskUsingNumberOfMaskBits:selectedAmountOfBits];
//RELEASE
[stringToNumber release];
}
There are some issues in the original code, I added //!i comments below:
- (void)subnetMaskByNumberOfSubnetBits:(id)sender{
NSNumberFormatter *stringToNumber = [[NSNumberFormatter alloc] init];
//!i: The [[NSNumber alloc] init] is unnecessary. You are creating a pointer to a dummy number
// that is immediately overwritten in the next line
NSNumber *selectedAmountOfBits = [[NSNumber alloc] init];
//!i: At this point, you overwrite the pointer stored in selectedAmountOfBits to point to a new
// NSNumber, returned by numberFromString:, and in the autorelease pool
selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
//!i: you are now leaking the number allocated via [[NSNumber alloc] init], as you no longer have
// a variable tracking the pointer to it
[self changeSubnetMaskUsingNumberOfMaskBits:selectedAmountOfBits];
[stringToNumber release];
//!i: You are calling -release on the number that is in the autorelease pool, not on the
// original number you allocated via [[NSNumber alloc] init]
[selectedAmountOfBits release];
}
You can fix this as follows:
- (void)subnetMaskByNumberOfSubnetBits:(id)sender{
NSNumberFormatter *stringToNumber = [[NSNumberFormatter alloc] init];
NSNumber *selectedAmountOfBits = [stringToNumber numberFromString:[sender objectValueOfSelectedItem]];
[self changeSubnetMaskUsingNumberOfMaskBits:selectedAmountOfBits];
//!i: You still need the -release here, as stringToNumber points to the
// NSNumberFormatter that you created using alloc/init
[stringToNumber release];
}

I have a memory leak in this objective-c method, can anyone tell me where?

I'm receiving an exc_bad_access somewhere in the code below. I don't understand where it is if anyone could shine any light on it? It's a method that takes in an NSMutableArray of dictionaries and sorts them by one of the elements in the dictionary. The memory leak is almost certainly in the bit with the block but I think i'm missing something fundamental in finding it...
-(NSMutableArray*)sortBicyclesByDistanceToDevice:(NSMutableArray*)inputArray{
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b){
NSNumber *first = [[a objectForKey:kDistanceFromDevice] objectForKey:kValue];
NSNumber *second = [[b objectForKey:kDistanceFromDevice] objectForKey:kValue];
return [first compare:second];}];
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
[arrayToHoldSorted release];
return [retVal autorelease];
}
Thanks
It looks like you assign retVal to an NSMutableArray through then reassign immediately after. The original alloced NSMutableArray will leak. That is:
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
Should be:
NSMutableArray *retVal = [arrayToHoldSorted mutableCopy];
Replace:
NSMutableArray *retVal = [[NSMutableArray alloc] init];
retVal = [arrayToHoldSorted mutableCopy];
With:
NSMutableArray *retVal = [arrayToHoldSorted mutableCopy];
You are leaking the first value of retVal.
There's more than one in there!
This line:
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
Is a memory leak since you immediately reassign the pointer. It should be removed. Just declare your array on the next line:
NSArray* arrayToHoldSorted = [inputArray sortedArrayUsingComparator...
This method returns an autoreleased object, so you don't need to release it later on.
A similar pattern with the mutable array. You alloc/init, then overwrite with a new object, giving another leak. Again, remove the alloc/init line and just declare in the next line. mutableCopy gives you an implicitly retained object, so you do need to autorelease it.
You seem to be under the impression that alloc/init is needed every time you declare an object variable. This is not the case.
You allocate arrayToHoldSorted (1) - which you never use as you then get an NSArray back from sortedArrayUsingComparator(2). And then you release it afterwards(3) when you don't own it. You do the same trick for retVal, allocating a NSMutableArray - then overwriting your reference to it by getting a new NSMutableArray from [arrayToHoldSorted mutableCopy];
NSArray *arrayToHoldSorted = [[NSArray alloc] init]; .. // 1
arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b) ..... // 2
[arrayToHoldSorted release]; // 3
Just assign the return NSArray from sortedArrayUsingComparator to a reference...
NSArray* arrayToHoldSorted = [inputArray sortedArrayUsingComparator:^(id a, id b) .....
I think the problem is that in this line:
return [retVal autorelease];
you release something that you have not retained. Also in this line:
NSArray *arrayToHoldSorted = [[[NSArray alloc] init];
you have an extra [, which does not help. But most importantly, you can use the static analyzer in XCode to diagnose this sort of bug, rather than pestering the good folk on StackOverflow.

Converting Decimal to String to Decimal

I copied this code from another post. I tried the example, however, I am getting a EXEC_BAD_ACCESS. From what I have read, this error happens when trying to use an object that has been deallocated, but I just don't see where I am doing that:
The call
...
float weighted_average = num_of_passes / total_of_all_passes;
NSString *newNumber = [[NSString alloc] init];
newNumber = [self formattedStringWithDecimal:weightedAverage]; //weighted average (float) = 15.875145
...
The Function
- (NSString *)formattedStringWithDecimal:(NSDecimalNumber *)decimalNumber
{
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2]; //two deimal spaces
[formatter setRoundingMode: NSNumberFormatterRoundHalfUp]; //round up
NSString *result =[NSString stringWithString:[formatter stringFromNumber:decimalNumber]];
[formatter release];
return result;
}
Call the method like this:
newNumber = [self formattedStringWithDecimal:[NSDecimalNumber numberWithFloat:15.434]];
You've tried to pass a primitive, but the method expects an object: an NSDecimalNumber. You've got to use the static convenience method numberWithFloat to create an object of that type.
And by the way, I have the feeling that
newNumber = [NSString stringWithFormat#"%.2f", 15.434];
could achieve the same result with less lines of code. Note this will not round up your number though.
You are returning an autoreleased object. Does the function that uses it retain it? If not, it could be released and then later (later run loop) its trying to be (re)used. Agreed on the enabling zombies to spot that kind of thing.

problems during object release

I have some problems during when and which object to be release
You can say my knowledge towards this is less
i have following conditions please suggest me the answer accordingly
situation-1
NSMutableString *str=[[NSMutableString alloc]initWithFormat:#"Hello World!"];
NSMutableArray *array=[[NSMutableArray alloc]init];
[array addObject:str];
Now when i tried to release str then usage of array affected in future...and Vice Versa
Tell me can i release both?
situation-2
NSMutableString *str=[[NSMutableString alloc]init];
str=#"Hello World !";
str=[self getData]; //calling a method which returns a string
[str release];
I think i am creating a memory leak here(how to solve it?)
please clear these situations
in the first situation, you'll need to call [str release]; after adding it to the array, like this:
NSMutableString *str = [[NSMutableString alloc] initWithString:#"Hello World!"];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:str];
[str release];
This way, array holds the only retain call on the string. Once you release array later, you won't have any memory leak issues.
I'm a little confused about the second situation. str here is a pointer. You seem to be assigning three different objects to to same pointer:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
str=#"Hello World !"; //second object
str=[self getData]; //third object
by the time you call [str release], you've created a memory leak because you've lost the first mutable string. The second time you called str =, you lost any way to access that first NSMutableString.
Assuming that you're looking to concatenate all of these (since you chose NSMutableString), you might try this:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
[str appendString:#"Hello World!"];
[str appendString:[self getData]];
[str release];
If the [self getData] method returns an autoreleased string, you'll be fine. If getData returns a retained string (if you used alloc and init), you'll need to assign it to an intermediate pointer and release it after adding it to str.
What is the need of creating the NSMutableString You can directly use NSString for this purpose

stringWithFormat vs. initWithFormat on NSString

I am wondering what differences such as disadvantages and/or advantages there are to declaring an NSString this way:
NSString *noInit = [NSString stringWithFormat:#"lolcatz %d", i];
as opposed to:
NSString *withInit = [[NSString alloc] initWithFormat:#"Hai %d", i];
What was the motivation of putting stringWithFormat instead of just having the initWithFormat way of initializing the string?
stringWithFormat: returns an autoreleased string; initWithFormat: returns a string that must be released by the caller. The former is a so-called "convenience" method that is useful for short-lived strings, so the caller doesn't have to remember to call release.
I actually came across this blog entry on memory optimizations just yesterday. In it, the author gives specific reasons why he chooses to use [[NSString alloc] initWithFormat:#"..."] instead of [NSString stringWithFormat:#"..."]. Specifically, iOS devices may not auto-release the memory pool as soon as you would prefer if you create an autorelease object.
The former version requires that you manually release it, in a construct such as this:
NSString *remainingStr = nil;
if (remaining > 1)
remainingStr = [[NSString alloc] initWithFormat:#"You have %d left to go!", remaining];
else if (remaining == 1)
remainingStr = [[NSString alloc] initWithString:#"You have 1 left to go!"];
else
remainingStr = [[NSString alloc] initWithString:#"You have them all!"];
NSString *msg = [NSString stringWithFormat:#"Level complete! %#", remainingStr];
[remainingStr release];
[self displayMessage:msg];
Here, remainingStr was only needed temporarily, and so to avoid the autorelease (which may happen MUCH later in the program), I explicitly handle the memory as I need it.