PDA

View Full Version : retain with archiving




daproject85
Apr 19, 2011, 02:12 AM
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 {
@private
NSString *name;
int grade;
}

@property (retain) NSString *name;
@property int grade;
@end


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?


thanks



jiminaus
Apr 19, 2011, 03:00 AM
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?

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.


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

@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 (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html). The Accessor Methods (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAccessorMethods.html) chapter goes particularly to answering your 2nd question.

The Cocoa Fundamentals Guide (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/Introduction.html) might also be useful.

daproject85
Apr 22, 2011, 02:26 AM
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.

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?


@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)?

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?

jiminaus
Apr 22, 2011, 06:07 AM
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.


.
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?


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.


.
i dont understand what you mean ???


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.


.
so why release the previously set object and retain the newly set object? whats the point of that?


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

Sydde
Apr 22, 2011, 11:29 AM
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
self.name = [coder decodeObjectForKey:@"EMPname"]; is functionally equivalent to what you wrote. Why use @property if you are not going to apply it consistently?