Releasing or Autoreleasing objects

Go To StackoverFlow.com

0

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?

2012-04-03 23:29
by Corb3nik


2

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];
}
2012-04-03 23:35
by UIAdam


0

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];
}
2012-04-03 23:37
by iccir
Thanks for clearing things up for me : - Corb3nik 2012-04-03 23:39
UIAdam is also correct - he got to it a few minutes before I did ; - iccir 2012-04-03 23:39