Am I releasing the pointer or the actual object?

Discussion in 'Mac Programming' started by zippyfly, Sep 16, 2009.

  1. zippyfly macrumors regular

    Joined:
    Mar 22, 2008
    #1
    Hi.

    Say, I alloc/init a pointer to an object:

    NSObject *newObject = [newObject alloc] init];

    Now, we add it to an NSArray with addObject:

    Now, we release the array.

    [array release];

    The retain count to newObject should be 1 right now (2 after adding to the array and 1 after array is released).

    When I issue [newObject release] is the memory to the POINTER *newObject being reclaimed or both the pointer and the pointed-to object?

    Relatedly, when array is released, does it just decrement the retain count or does it decrement the retain count (for newObject) AND also releases the pointed-to object, leaving the pointer (which then points to a memory location that isn't actually being used)?

    Thanks.
     
  2. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #2
    Sorry, just wanted to append a related question and this might make it even clearer for me.

    So I alloc/init the object.

    Now I add it to the array.

    Now, I RELEASE the object BEFORE I release the array.

    The object is still around right?

    So when I release the ARRAY, then all the memory should be properly cleaned right?

    (I guess my question is, I should release all objects first, to ensure their retain counts are decremented to 1, BEFORE any release is issued to arrays holding them, correct? Not the other way around?)
     
  3. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #3
    You're releasing the object, not the pointer to it. If you want to ensure that you don't accidentally use an invalid pointer, you can set it to nil after releasing it for safety. The array will handle releasing its contents when it's deallocated (not when it's released), so the order doesn't matter.

    allocate array - array retain count is 1
    allocate object - object retain count is 1
    add object to array - object retain count is 2
    release object - object retain count is 1
    release array - array retain count is 0
    array's dealloc is called by its retain count reaching 0 - object retain count is 0
    object's dealloc is called its retain count reaching 0
     
  4. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #4
    Just to add:
    You will never "release" a pointer. A pointer is not an Object. 99.9% of the time, your pointers will be stack-local, so they will just go away when the stack-frame gets popped. No need to worry about them at all. .1% of the time or less you may, for some reason, have used malloc or one of its friends to get some memory for a pointer or 20. In this case, you would need to free this memory when you're done with it, but that is definitely a different mechanism than release.

    -Lee
     
  5. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #5
    OK great; thanks guys. I was thinking the pointer and the final object are somehow "paired up" -- so if a pointer is treated as any variable, if I declare a pointer and object inside a loop, and the loop exits without me releasing the object, does that mean the object is orphaned in memory, while the pointer to it has gone out of scope and was popped off that stack frame?
     
  6. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #6
    Once you leave the block (function, loop, if, stand-alone, etc.) that a variable is declared in, it's gone. So you get the memory back for the variable, but if that was the only pointer storing the address of an object, you can't get to that object any more. If you're using garbage collection, you're fine... the last reference to that thing is gone, it will get reaped by the GC system. If you're using autorelease pools, or straight-up retain/release, and you didn't release/autorelease the Object, you're going to be leaking memory.

    -Lee
     
  7. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #7
    Right, I get it perfectly now; thanks for your explanation.
     
  8. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #8
    How come this still works?

    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	NSString *myString = [[NSString alloc] initWithString:@"abcdefg"];
    	
    	NSString *myPointer = myString;
    	
    	[myString release];
    	
    	NSLog(@"%@",myPointer);
    	
    	NSLog(@"%@",myString);
    	
        [pool drain];
        return 0;
    }
    
    Is that because even though the memory is released, the physical RAM has not been overwritten and the pointer(s) still point to the address of the object data?

    I tried releasing three times but still get the printout.

    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	NSString *myString = [[NSString alloc] initWithString:@"abcdefg"];
    	
    	NSString *myPointer = myString;
    	
    	[myString release];
    
    	[myString release];
    
    	[myString release];
    	
    	myString = NULL;
    	
    	NSLog(@"%@",myPointer);
    	
    	NSLog(@"%@",myString);
    	
        [pool drain];
        return 0;
    }
    
     
  9. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
  10. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #10
    OK - I have a brain wave (which I need to verify); is this because the initiWithString method actually allocates into the autorelease pool and thus any manual release is ignored?
     
  11. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #11
    Offhand I would suspect that's an oddity of NSString. Constant strings actually bypass retain/release entirely and aren't really "allocated". Try it with an NSMutableString instead.
     
  12. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #12
    Much weirdness:

    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	NSMutableString *myString = [[NSMutableString alloc] initWithString:@"abcdefg"];
    	
    	NSMutableString *myPointer = myString;
    	
    	[myString release];
    	
    	NSLog(@"myPointer is %@",myPointer);
    	
    	NSLog(@"myPointer is %@",myPointer);
    	
    	NSLog(@"myString is %@",myString);
    	
    	NSLog(@"myString is %@",myString);
    	
    	[pool drain];
        return 0;
    }
    Code:
    Running…
    2009-09-17 11:48:36.033 TestApp[16101:a0f] myPointer is myPointer is 
    2009-09-17 11:48:36.042 TestApp[16101:a0f] myPointer is <NSCFLocale: 0x10010cb00>
    2009-09-17 11:48:36.042 TestApp[16101:a0f] myString is <NSCFLocale: 0x10010cb00>
    2009-09-17 11:48:36.043 TestApp[16101:a0f] myString is <NSCFLocale: 0x10010cb00>
    
    Debugger stopped.
    Program exited with status value:0.
    I guess the weirdness is expected.

    (Commenting out the release makes this work as expected.)
     
  13. Catfish_Man macrumors 68030

    Catfish_Man

    Joined:
    Sep 13, 2001
    Location:
    Portland, OR
    #13
    What you're seeing there is that a different (cocoa-allocated) object is now in the memory your string was using. This is why nil-ing after releasing can be a good defensive measure.
     
  14. zippyfly thread starter macrumors regular

    Joined:
    Mar 22, 2008
    #14
    Thanks. I think my head is fairly wrapped around this thing now, and if not then maybe just another couple more days of studying.
     

Share This Page