Re: half-initialized objects during decoding (Re: Persistance)
Re: half-initialized objects during decoding (Re: Persistance)
- Subject: Re: half-initialized objects during decoding (Re: Persistance)
- From: "Erik M. Buck" <email@hidden>
- Date: Thu, 11 Oct 2001 11:13:24 -0500
The following is an astute observation. This problem also occurs with C++
constructors. Many C++ class libraries use the idiom of having a separate
init member function that must be called after an instance is created but
before it is useful. The constructors are implemented to do as little as
possible.
Cocoa uses the same technique. That is what -awakeFromNib
and -awakeAfterUsingCoder: are for. The -initWithCoder: method should be
implemented to do as little as possible and make few assumptions about the
state of referenced objects. Final initialization based of referenced
objects should take place in an awake method.
All init methods have this reference to "half initialized" objects problem
including -initWithCoder: which is just another init...
Maybe the solution is to make programmers aware of the issue and stop
calling it a problem. I admit that I have been writing -initWithCoder:
methods for so long that I don't think about it any more.
The -initWithCoder: methods always just assign instance variables.
>
It seems to me that you can force yourself into the same
>
situation in other cases:
>
>
@implementation A
>
>
- init
>
{
>
...
>
b = [[B alloc] initWithA:self];
>
...
>
}
>
@end
>
>
@implementation B
>
- initWithA:(A *) anA
>
{
>
...
>
x = [anA someValue];
>
...
>
}
>
@end
>
>
If anA is half-initialized, x's value could be junk. I think
>
that in that case it is obviously the programmer's
>
responsibility not to create this kind of coupling or to
>
order messages so that "it works". Why should the
>
unarchiving situation be different?
>
>
> One historical insidious manifestation of this problem
>
> is when an object A implements internal reference
>
> counting in one of its fields. During decoding, B gets
>
> a reference to A (with -decodeObject) and retains it,
>
> invoking -retain on the half-initialized A.
>
> A's initWithCoder: proceeds, and at some point sets the
>
> ref count field to 0 (initializing it), but this blows
>
> away B's retain (and anybody else's).
>
>
Why is initWithCoder assuming that the retain count should
>
be initialized to 0? Is this how NSUnarchiver returns
>
autoreleased objects? In that case, something like x = [[X
>
alloc] initWithCoder:aCoder]; is also very wrong, since
>
everybody would assume that the retain count is 1.
>
>
I would have imagined that initializing a retain count (to 1
>
rather than 0) should be left to allocWithZone, and that
>
init... methods should leave it untouched. This would be
>
coherent with all the doc I've seen about alloc and copy,
>
statements like (in Object Ownership and Disposal): "If you
>
create an object (using alloc or allocWithZone:) or copy an
>
object (using copy, copyWithZone:, mutableCopy, or
>
mutableCopyWithZone:), you alone are responsible for
>
releasing it. If you didn't directly create or copy the
>
object, you don't own it and shouldn't release it." This
>
cannot work if init methods mess with retain counts.
>
>
And not messing with the retain count in initWithCoder would
>
remove that insidious hitorical problem.
>
>
Or am I missing something?
>
>
Marco Scheurer
>
Sen:te, Lausanne, Switzerland http://www.sente.ch
>
_______________________________________________
>
cocoa-dev mailing list
>
email@hidden
>
http://www.lists.apple.com/mailman/listinfo/cocoa-dev