Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone +;(无效)未调用初始化(目标C)_Iphone_Objective C - Fatal编程技术网

Iphone +;(无效)未调用初始化(目标C)

Iphone +;(无效)未调用初始化(目标C),iphone,objective-c,Iphone,Objective C,我的方法+(void)initialized没有被调用,我对Objective C非常陌生。代码在iPhone游戏开发书中,我必须显式调用该方法才能工作。.m文件中的代码是: ResourceManager *g_ResManager; @implementation ResourceManager //initialize is called automatically before the class gets any other message, per from http://sta

我的方法+(void)initialized没有被调用,我对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

外部资源管理器*g\u ResManager//paul来自NSObject的文档:

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


+initialize
仅在发送类(它是第一条消息)之前调用。在向类发送消息之前,不会调用
+initialize
方法

例如:


如果调用
[[MyObject alloc]init]
+initialize
在将
alloc
发送到MyObject之前,对MyObject调用
+initialize

+initialize
直到您向类的实例发送一些消息时才会调用。你发信息了吗

一个可能的问题可能是您从代码的另一部分向g_ResManager发送了一条消息? 这行不通,因为:

  • g_ResManager
    在启动时为零
  • 您向
    g\u ResManager
    发送一条消息,即
    nil
  • Objective-C运行时算作“向类发送消息”的不是它在源代码中的语法外观,而是真正的对象和发送的消息
  • 因此,在本例中,
    nil
    获取消息,
    nil
    不是
    ResourceManager
    的实例,因此也不会调用
    +initialize
  • 我会把你的代码修改如下:首先,在.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在评论中所说,在这种情况下,您可以完全取消
    +初始化
    。我改成

    @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
    的版本应该是线程安全的。请参阅中的讨论。

    请注意,当您不自己分配对象时,应该保留它。例如:

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

    否则它将无法存活足够长的时间,无法使用几次(指针仍然是
    !nil
    ,但不再有效)。

    这正是发生的情况。非常感谢!!!我来自Java,在这种情况下总是得到一个NullPointerException:D再次感谢!很高兴知道它起作用了。不管怎么说,它只是表明有那么多蹩脚的iPhone编程书是由没有经验的人写的。没有一个理智的Obj-C开发人员会制造这样一个全局外部实例变量。制作一个
    +sharedFoo
    返回共享实例是一种习惯用法。请告诉我。这真的很有道理。使用单例模式并声明一个外部变量。但因为我对Objective-C的知识水平较低,所以就这样离开了。现在一切都好了。没有外部变量了。再次感谢。关于+initialize的工作原理,Yuji是绝对正确的,但是这里不需要使用+initialize。只要在+sharedResourceManager中初始化g_ResManager(如果为零)。在这种情况下,您甚至可以将g_ResManager设置为静态函数;不需要文件static.extern实际上是旧C语言的遗留。正如您所见,除非您必须与基于C的库交互,否则在Objective-C中应该避免使用它。也谢谢您的回答,Jasarien。这是真的,但它不是问题的答案。好的,我应该对此发表评论。抱歉。@EricGoldberg此方法不拥有保留值;它存储在一个静态变量中。这是正确的代码。