retain with archiving

Discussion in 'Mac Programming' started by daproject85, Apr 19, 2011.

  1. daproject85, Apr 19, 2011
    Last edited: Apr 19, 2011

    macrumors member

    Apr 13, 2011
    hey guys question:

    i was doing an exercise and the book said to write the following snippet

    -(id) initWithCoder:(NSCoder *) coder {
        name = [[coder decodeObjectForKey:@"EMPname"] retain];
        NSNumber *gradeBox = [coder decodeObjectForKey:@"EMPgrade"];
        grade = (int) [gradeBox integerValue];
        return self;
    and said we need to retain the object name (defined in my class definition). my question is why do we need to retain this object? i mean ... in my main functions i have

    Employee *fred = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/Users/YOURDIRECTORY/bob.plist"];
    to make this more clear here is my class interface
    @interface Employee : NSObject {
        NSString *name;
        int grade;
    @property (retain) NSString *name;
    @property int grade;
    So two questions

    1. which calls initwithcoder, and name and grade are placed into the new object from my class. so why bother retaining it? i understand that decodeobject for key uses autorelease itself, so wouldn't that "autorelease" kick in after i do [fred release] in my main?

    2. WHY use retain in @property (retain) NSString *name;??? i believe @property (matched with synthesize) must makes setters and getters.. so why use retain?

  2. jiminaus, Apr 19, 2011
    Last edited: Apr 19, 2011

    macrumors 65816


    Dec 16, 2010
    Objects always exist independently in Objective-C. Objects are not "placed in" other object. Only a pointer to the other object is stored. If you know UML, there is no aggregation relationships in Objective-C, only containment relationships.

    So the retain is not in regards to the object itself, but the pointers to other objects, in this case name. Without the retain when name is decoded, the NSString object pointed to by name would be released (and probably dealloced) while fred still had a pointer to it. Thus fred would have a dangling pointer to a dead object.

    autorelease doesn't "kick in". It happens when the closest autorelease pool is drained. Usually the closest autorelease pool is one created by NSRunLoop.

    @synthesise does implement the getter and setter for a property. But how is it to implement it? Does it simply assign the incoming value to the instance variable (assign)? Does it release the previously set object and retain the newly set object (retain)? Does it release the previously set object and set a distinct copy of the newly set object (copy)?

    Read (again) carefully the whole of the Memory Management Programming Guide. The Accessor Methods chapter goes particularly to answering your 2nd question.

    The Cocoa Fundamentals Guide might also be useful.
  3. thread starter macrumors member

    Apr 13, 2011

    so lets say i only have main and my [pool drain] is at the end of main function. In this case i wouldn't need to retain anything because ones my program reaches the end of main my program is done right? or do u generally have more than one NSRUNLOOP?

    i dont understand what you mean ???
    here is why i have in my .h file
    @property (retain) NSString *name;
    and here is what i have in my .m file
    @synthesize name;
    so why release the previously set object and retain the newly set object? whats the point of that?
  4. macrumors 65816


    Dec 16, 2010
    Darealjakesh, red text, like capatalisation, is akin to shouting and is the quickest may to peeve someone off. So I'll shallow my anger and try to calmly answer your questions.

    Yes, if this is a command-line program and you don't run an NSRunLoop, then it is as you say, the release won't be sent until the program reaches the end of main where drain in sent to the one-and-only autorelease pool.

    But this only the simplest, and least common, case. The memory management rules you're arguing against are set up for the more complex, and more common, case of GUI programs with an NSRunLoop.

    You're creating a rubbish program that is only going to consume more and more memory as time goes on if you don't properly retain and release your objects. It a stupid habit to get into because you only going have to start doing the right thing once your program becomes non-trivial, or start creating non-trivial programs.

    Really, if don't want to be bothered about memory-management, just turn on garbage collection.

    Go and read the Memeory Management Guide as I suggested. It shows, at least conceptually, how the compiler creates the getter and setter methods for each of the assign, retain, and copy options.

    Because otherwise you'll leak memory. The previously set object won't ever get deallocated.
  5. macrumors 68000


    Aug 17, 2009
    Two thoughts:
    -initWthCoder: is an init function, so you should probably have the "self = [super init]" bit in there (if the superclass conforms to NSCoding protocol, you might want -initWithCoder: in the call to super).

    Simplify. If you are using @property, get in the habit of using dot-notation to make sure your ivars are handled properly. I think
    Code: = [coder decodeObjectForKey:@"EMPname"];
    is functionally equivalent to what you wrote. Why use @property if you are not going to apply it consistently?

Share This Page