Retaincount increases on getters?

Discussion in 'Mac Programming' started by tankit, Nov 17, 2008.

  1. tankit macrumors newbie

    Joined:
    Nov 17, 2008
    #1
    Hi there,

    I have the following example class. The Apple documentation states that retain, copy and assign attributes to property only affects the setters.

    https://developer.apple.com/iphone/....html#//apple_ref/doc/uid/TP30001163-CH17-SW2

    However I have noticed the retaincount is increased everytime I make a call to a getter.

    #import <Cocoa/Cocoa.h>

    @interface Person : NSObject {
    @private NSString *name;
    @private NSNumber *age;
    }

    @property (readwrite, retain) NSString *name;
    @property (readwrite, retain) NSNumber *age;

    + (id) create: (NSString *) name andAge: (NSNumber *) age ;
    - (id)init;
    - (void) printState;

    @end

    with the implementation

    #import "Person.h"


    @implementation Person

    @synthesize name;
    @synthesize age;

    - (id) init
    {
    if ( self = [super init] )
    {
    [self setName:mad:""];
    [self setAge:nil];
    }
    return self;
    }

    + (id) create: (NSString *) name andAge: (NSNumber *) age
    {
    Person* person = [[[Person alloc] init] autorelease];
    [person setName: name];
    [person setAge:age];
    return person;
    }

    - (NSNumber *) age
    {
    return self->age;
    }

    - (void) printState
    {

    NSLog(@"Name of person is %@ age %@",[self name],[self age]);
    NSLog(@"Retain count for name and age is %lu, %lu",[name retainCount],[age retainCount]);

    }

    - (void) dealloc
    {
    [self setAge:nil];
    [self setName:nil];
    [super dealloc];
    }

    @end

    main.m

    #import <Cocoa/Cocoa.h>
    #import "Person.h"

    int main(int argc, char *argv[])
    {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSString *name = [NSString stringWithString: @"Fred"];
    NSNumber *age = [NSNumber numberWithInt:30];
    Person *person = [Person create:name andAge:age];

    [person printState];
    [person printState];
    [person printState];

    [pool release];

    }

    Nov 18 07:23:22 Byron MyTool[2074]: Name of person is Fred age 30
    Nov 18 07:23:22 Byron MyTool[2074]: Retain count for name and age is 2147483647, 3
    Nov 18 07:23:22 Byron MyTool[2074]: Name of person is Fred age 30
    Nov 18 07:23:22 Byron MyTool[2074]: Retain count for name and age is 2147483647, 4
    Nov 18 07:23:22 Byron MyTool[2074]: Name of person is Fred age 30
    Nov 18 07:23:22 Byron MyTool[2074]: Retain count for name and age is 2147483647, 5

    If I supply an implementation that reflects a simply return:

    - (NSNumber *) age
    {
    return self->age;
    }


    then output is:

    ov 18 07:27:38 Byron MyTool[2122]: Name of person is Fred age 30
    Nov 18 07:27:38 Byron MyTool[2122]: Retain count for name and age is 2147483647, 2
    Nov 18 07:27:38 Byron MyTool[2122]: Name of person is Fred age 30
    Nov 18 07:27:38 Byron MyTool[2122]: Retain count for name and age is 2147483647, 2
    ... and continues the same


    therefore I believe the code generated for a retain or copy for a getter must be sometime like:

    - (NSNumber *) age
    {
    return [self->age retain];
    }

    Can anyone confirm this behaviour? Should I be concerned or will I have to place an autorelease on every getter call.

    (Note: I have disabled GC in Xcode)
     
  2. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #2
    After thinking about it i believe i shouldn't be worried.

    Each object returned from a getter is a super class of NSObject. Since these were created using the in-build methods (not alloc) then they are registered with the auto release pool. When the pool is released then these retain counts are cleared.

    Is this correct assumption?
     
  3. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #3
    To summaries this I believe the generated code for a getter is:

    - (NSString *)name {
    return [[aName retain] autorelease];
    }

    This would only apply to assign/retain.
     
  4. darkwing macrumors 65816

    Joined:
    Jan 6, 2004
    #4
    My app has a retain property called token. I put in the following code to test your theory and it seems you are right. After I released the autorelease pool, the local value I got was invalid.

    Code:
    NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
        self.token = [NSMutableString stringWithString:@"testing"];
        NSLog(@"ret %d", [self.token retainCount]);
        NSString *str = self.token;
        self.token = nil;
        NSLog(@"%@ %d", str, [str retainCount]);
        [p release];
        NSLog(@"%@ %d", str, [str retainCount]);
     
  5. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #5
    Does token have a copy or retain attribute for the property? What happens if you changed self.token = nil to [self token] release?

     
  6. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #6
    This is what the nonatomic keyword is for. Check out the Atomicity section.
     
  7. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #7
    Only applicable for multi-threaded code. Wraps the variable in a lock to ensure no other thread modifies the variable during the call. I will give the nonatomic option a go and see what the results are.

    Cheers

     
  8. garethlewis2 macrumors 6502

    Joined:
    Dec 6, 2006
    #8
    You're right with the retain count increasing as auto generated code is giving you back an autoreleased/retained version for you to work with. Your simple getter is simply returning the reference to the object. Normally for String objects, you would copy, not retain. Even though you believe you are referring to an NSString, it could actually be an NSMutableString, and you would not want the data changing half-way through the app run time.
     
  9. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #9
    changing the property attributes to

    @property (readwrite, nonatomic, copy) NSNumber *age;

    with the nonatomic keyword it does change the dynamics. The generated code has removed the retain and autorelease.

    [[aName retain] autorelease];

    it is now a simple return as the retaincount is not increasing with multiple getter calls. The default is to allow multiple threads to handle the return object without the fear of it been GC'd. Using the nonatomic keyword removes this, however if multiple threads attempted to utilised the return object there could be a risk one of these threads may release this object (bad situation) and the GC will clean the data from the object.

     
  10. darkwing macrumors 65816

    Joined:
    Jan 6, 2004
    #10
    I did say it has a "retain" property. So yes, it has a retain attribute.
     
  11. tankit thread starter macrumors newbie

    Joined:
    Nov 17, 2008
    #11
    Sorry...needed another coffee

     

Share This Page