Designated Initializer, retain parameters?
I have the following designated initializer:
-(id) initWithName:(NSString*)name;
and the following default initializer:
-(id) init { return [self ini开发者_JAVA百科tWithName:@"foo"]; }
What kind of object does the designated initializer receive than? A released or a autoreleased?
given the following initializer:
-(id) init { return [self initWithName:[NSString new]]; }
I would receive a retined object. The default initializer would never have a chance to release it, so I shouldn't retain it?. Now imagine instead of NSString this would be a class that does not provide a convenience initializer (like -myClassWithParam:). Do I need to provide a convenience initializer to enable in place constructing?
The initializer (designated or not) should never care about the ownership of objects it receives as arguments. If it wants to keep the object, it has to copy or retain it, no matter where the argument comes from. Your designated initializer initWithName
should copy the name
argument in its implementation.
Memory management for NSString literals is a special case, since these objects are never released and just ignore retain
, release
, and autorelease
.
Your third example has a leak, since the name argument string object is never released.
You should always send an autoreleased object (or release it after) to your initialisers - the memory management rules don't change in this instance.
In your example, I'd do this:
-(id) init {return [self initWithName:[[NSString new] autorelease]]]}
This will fix your memory leak and still allow in place constructing.
However, you don't need an extra retain when passing through your initializers - what you're doing with self
is fine. As a rule, +alloc
retains the object once, and -init
methods don't retain further. -init
will be called many times as the [super init]
calls go up the class tree, but the object should only be retained once when it's finally returned to the caller - +alloc
has already done this for you.
However, convenience methods that don't contain the words init, copy or new should return an autoreleased object. As an example:
+(MyObject *)objectWithName:(NSString *)aName {
return [[[MyObject alloc] initWithName:aName] autorelease];
}
FWIW, I normally have -init as my designated initializer, so in case I forget and send -init to an object (or someone else does the same), you don't get a trash object. For instance:
-(id)init {
if (self = [super init]) {
[self setName:[[NSString new] autorelease]];
myReallyImportantiVar = [[NSArray alloc] init];
// etc;
}
return self;
}
-(id)initWithName:(NSString *)aName {
if (self = [self init]) {
[self setName:aName];
}
return self;
}
This may be slightly less efficient (when you're using -initWithName:, setName is called twice), but it's much safer.
精彩评论