Open Quuxplusone opened 13 years ago
Is this part of the Cocoa conventions?
(In reply to comment #1)
> Is this part of the Cocoa conventions?
Yes. I'm including some sample code which demonstrates the convention (run
with "cc -o /tmp/InitializeTest InitializeTest.m -framework Foundation &&
/tmp/InitializeTest"). Note that AnySubclass, MyGoodSubclass, and
MyBlissfulSubclass all log invocations from [MySuperclass initialize], while
MyForgetfulSubclass does not. (Since [AnySubclass self] is called first, it
actually logs twice: once with self == MySuperclass and once with self ==
AnySubclass.)
I believe this has been the convention since 1989; or at least since 1993, when
the behavior was documented in "Object-Oriented Programming and the Objective C
Language" (by NeXT Publications): The runtime generates a single +initialize
for each class before sending it any other messages. The +initialize message
is sent whether or not a subclass implements it, so when implementing
+initialize you can expect to be called once for each subclass. (Unless, of
course, the subclass fails to call [super initialize]!) The 1993 documentation
for +initialize included two techniques for protecting code that really only
wants to be called once (testing self to see if it's being called for the main
class rather than a subclass; or testing a static initialization variable).
That said, I should note that the current NSObject class documentation has
edited the description of +initialize slightly since that 1993 publication: it
shows just one technique for guarding code you want to run once (rather than
two)—and unfortunately it now also suggests that +initialize shouldn't
typically call [super initialize] "since the runtime sends appropriate
initialize messages automatically." I'm not quite sure when this advice was
introduced into the documentation; in 2007 I filed RADAR 5480173 pointing out
that that's a departure from the actual convention and suggesting they correct
the advice. (That suggestion was introduced relatively recently; the
aforementioned 1993 documentation for +initialize reads largely the same
otherwise.)
Failing to call [super initialize] leads to inconsistent and sometimes
difficult to track down results where a subclass will stop working when someone
introduces a new +initialize method which doesn't call [super initialize].
(This is much the same problem as when a subclass fails to call [super init].)
My hope is that adding a warning will help prevent many of those bugs!
Thanks!
Ken
#import <Foundation/Foundation.h>
@interface MySuperclass : NSObject
@end
@interface AnySubclass : MySuperclass
@end
@interface MyGoodSubclass : MySuperclass
@end
@interface MyForgetfulSubclass : MySuperclass
@end
@interface MyBlissfulSubclass : MySuperclass
@end
@implementation MySuperclass
+ (void)initialize;
{
NSLog(@"MySuperclass: +[%@ %@] begin", NSStringFromClass(self), NSStringFromSelector(_cmd));
[super initialize];
NSLog(@"MySuperclass: +[%@ %@] end", NSStringFromClass(self), NSStringFromSelector(_cmd));
}
@end
@implementation AnySubclass
@end
@implementation MyGoodSubclass
+ (void)initialize;
{
NSLog(@"MyGoodSubclass: +[%@ %@] begin", NSStringFromClass(self), NSStringFromSelector(_cmd));
[super initialize];
NSLog(@"MyGoodSubclass: +[%@ %@] end", NSStringFromClass(self), NSStringFromSelector(_cmd));
}
@end
@implementation MyForgetfulSubclass
+ (void)initialize;
{
NSLog(@"MyForgetfulSubclass +[%@ %@] begin", NSStringFromClass(self), NSStringFromSelector(_cmd));
NSLog(@"MyForgetfulSubclass +[%@ %@] end", NSStringFromClass(self), NSStringFromSelector(_cmd));
}
@end
@implementation MyBlissfulSubclass
@end
int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[AnySubclass self];
[MyGoodSubclass self];
[MyForgetfulSubclass self];
[MyBlissfulSubclass self];
[pool release];
return 0;
}
P.S. — To be clear, I'm not trying to stir up anything; I've always thought that calling [super initialize] was as non-controversial as calling [super init]. My documentation RADAR hasn't seen any feedback, but I've been assuming that just means it's a low priority. If there /is/ controversy over this convention, I'm happy to participate in dialog about that in a more appropriate forum (if I can figure out where that should be!).
Not being a big Objective-C programmer myself, I was mainly wondering if this
*was* documented somewhere. I can readily loop in the AppKit guys to confirm
the convention, and discuss it with them.
You mentioned a documentation radar; do you have the number on hand?
(In reply to comment #4)
> Not being a big Objective-C programmer myself, I was mainly wondering if this
> *was* documented somewhere. I can readily loop in the AppKit guys to confirm
> the convention, and discuss it with them.
That sounds great. Thank you!
> You mentioned a documentation radar; do you have the number on hand?
Yes, it's <rdar://5480173>.
Thanks again,
Ken
cloned to rdar://problem/10502477
I just received notification that rdar://problem/5480173 has finally been fixed: the documentation for +initialize now indicates that it's appropriate to call [super initialize].
It would be great if the static analyzer would add an option to warn developers when they forget to call [super initialize] from +initialize, since this can be a source of subtle errors!
Overview:
Discussion: