+ (void) initialize not called (Objective C)
My method + (void) initialized is not called and I'm very new in Objective C. The code is in the book iPhone Game Development and I have to call the method explicitly to work. The code in the .m file is that:
ResourceManager *g_ResManager;
@implementation ResourceManager
//initialize is called automatically before the class gets any other message, per from http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like
+ (void) initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
g_ResMana开发者_StackOverflow社区ger = [[ResourceManager alloc] init];
}
}
...
@end
But in the .h file a external declaration of the variable is made:
extern ResourceManager *g_ResManager; //paul <3's camel caps, hungarian notation, and underscores.
@interface ResourceManager : NSObject {
...
}
...
@end
I tried everything (remove the external, put static in the .m declaration) and always get compilation errors. The code above compiles but the method initialize is never called (putted a breakpoint to see that).
Some clue?
+initialize
is not called until you send some message to an instance of the class. Did you send a message?
One possible problem might be that you sent a message to g_ResManager
from another portion of your code?
That won't work, because:
g_ResManager
is nil at the launch time.- You send a message to
g_ResManager
, which isnil
. - What Objective-C runtime counts as "sending a message to a class" is not what it looks syntactically in the source code, but the real object and the message sent.
- So, in this case,
nil
gets the message,nil
is not an instance ofResourceManager
, so+initialize
is not called either.
I would change your code as follows: first, in .m,
static ResourceManager *g_ResManager;
@implementation ResourceManager
//initialize is called automatically before the class gets any other message
+ (void) initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
g_ResManager = [[ResourceManager alloc] init];
}
}
+(ResourceManager*)sharedResourceManager
{
return g_ResManager;
}
...
@end
and then in .h, I would just have
@interface ResourceManager:NSObject {
...
}
+(ResourceManager*)sharedResourceManager
@end
Then, you can always use [ResourceManager sharedResourceManager]
.
In fact, as Rob says in the comment, you can totally do away with +initialize
in this case. Change .m to something like
@implementation ResourceManager
+(ResourceManager*)sharedResourceManager
{
static ResourceManager *g_ResManager=nil;
if(!g_ResManager){
g_ResManager=[[ResourceManager alloc] init];
}
return g_ResManager;
}
...
@end
This is the idiom I always use personally. But I warn you this is not completely thread safe! It should be OK as long as you call [ResourceManager sharedResourceManager]
once before spawning threads, which I would almost always do anyway, but that's one thing to keep in mind. On the other hand, the version above using +initialize
should be thread safe as is, thanks to the well-defined behavior of +initialize
. See discussions in this blog post.
From the documentation for NSObject:
The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program. (Thus the method may never be invoked if the class is not used.) The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses.
+initialize
is only called before you send a class it's first message. Until you send a message to the class, the +initialize
method is not called.
Eg:
If you call [[MyObject alloc] init];
, +initialize
is called on MyObject just before alloc
is sent to MyObject.
Be aware that when you don't allocate an object by yourself, you should retain it. Example:
+ (NSPredicate *)somePredicate
{
static NSPredicate *predicate = nil;
if (!predicate) {
predicate = [NSPredicate predicateWithFormat:@"status == 2"];
[predicate retain];
}
return predicate;
}
Otherwise it doesn't survive long enough to be used a few times (the pointer still is !nil
, but not valid any more).
精彩评论