+(void)初始化未调用(Objective C)

时间:2010-02-01 16:52:58

标签: iphone objective-c

我的方法+(void)初始化没有被调用,我在Objective C中是非常新的。代码在iPhone游戏开发的书中,我必须明确地调用该方法才能工作。 .m文件中的代码是:

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_ResManager = [[ResourceManager alloc] init];
    }
}

...

@end

但是在.h文件中,变量的外部声明是:

extern ResourceManager *g_ResManager; //paul <3's camel caps, hungarian notation, and underscores.

@interface ResourceManager : NSObject {
   ...
}
...
@end

我尝试了所有内容(删除外部,在.m声明中放置静态)并始终遇到编译错误。上面的代码编译但是从不调用方法初始化(推断断点以查看)。

一些线索?

3 个答案:

答案 0 :(得分:14)

在您向类的实例发送一些消息之前,不会调用

+initialize。你发了消息吗?

一个可能的问题可能是您从代码的其他部分向g_ResManager发送了邮件? 那是行不通的,因为:

  1. g_ResManager在发布时为零。
  2. 您向g_ResManager发送了一条消息,nil
  3. 什么Objective-C运行时计为“向类发送消息”并不是它在源代码中的语法,而是真实对象和发送的消息。
  4. 因此,在这种情况下,nil会收到消息,nil不是ResourceManager的实例,因此也不会调用+initialize
  5. 我会按如下方式更改您的代码:首先,在.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
    

    然后在.h,我会有

    @interface ResourceManager:NSObject {
    ...
    }
    +(ResourceManager*)sharedResourceManager
    @end
    

    然后,您可以随时使用[ResourceManager sharedResourceManager]

    事实上,正如Rob在评论中所说,在这种情况下,你可以完全取消+initialize。将.m更改为类似

    的内容
    @implementation ResourceManager
    
    +(ResourceManager*)sharedResourceManager
    {
         static ResourceManager *g_ResManager=nil;
         if(!g_ResManager){
             g_ResManager=[[ResourceManager alloc] init];
         }
         return g_ResManager;
    }
    ...
    
    @end
    

    这是我个人常用的习语。但我警告你这不是完全线程安全的!只要你在产生线程之前调用[ResourceManager sharedResourceManager]一次就应该没问题了,我几乎总是这样做,但这是要记住的一件事。另一方面,由于+initialize的明确定义的行为,使用+initialize的上述版本应该是线程安全的。请参阅this blog post中的讨论。

答案 1 :(得分:6)

来自NSObject的文档:

  

运行时将initialize发送给每个   一个程序中的类恰好一次   就在课前,或任何课程   继承自它,发送它   来自程序内的第一条消息。   (因此可能永远不会调用该方法   如果没有使用该类。)运行时   发送初始化消息   类以线程安全的方式。   超类收到此消息   在他们的子类之前。

+initialize仅在您发送第一条消息之前调用。在向课程发送消息之前,不会调用+initialize方法。

例如:

如果您致电[[MyObject alloc] init];,则会在+initialize发送至MyObject之前在MyObject上调用alloc

答案 2 :(得分:0)

请注意,如果您不自行分配对象,则应保留它。例如:

+ (NSPredicate *)somePredicate
{
    static NSPredicate *predicate = nil;
    if (!predicate) {
        predicate = [NSPredicate predicateWithFormat:@"status == 2"];
        [predicate retain];
    }
    return predicate;
}

否则它的存活时间不足以使用几次(指针仍为!nil,但不再有效。)