从plist初始化Objective-C字符串常量

时间:2009-08-28 20:32:35

标签: iphone objective-c constants

我使用'extern'和'const'关键字在我的iphone程序中定义了一个常量类,如下所示:

Constants in Objective-C

此时,我试图从plist文件的内容初始化一些字符串常量,而不是在类中定义,例如,而不是:

// Constants.m
NSString * const MyConstant = @"a constant";

我想从plist文件中初始化它。到目前为止,我已经使用静态+(void)load方法进行了测试,但我并不完全满意,例如:

// Constants.m
NSString * ALERT_QUIT_TITLE;

@implementation Constants

+ (void)load {
// this controller contains all the strings retrieved from the plist file
    LabelsController *labels = [LabelsController instance];     
    ALERT_QUIT_TITLE = labels.alertQuitTitle;       
}

@end

使用日志调用我可以验证在app启动时尽早调用加载代码,甚至在AppDelegate构造函数之前。但是,我认为这种方法有两件事情不太好:

  1. 我必须删除'const'关键字,否则我会收到编译错误,因为我正在尝试初始化一个定义为常量的变量
  2. 我收到一些关于自动释放池的警告信息:
  3. *** _NSAutoreleaseNoPool():类NSPathStore2的对象0x50b330自动释放,没有池到位 - 只是泄漏     堆栈:(0x905caf0f 0x904d8647 0x904e039f(etc)

    我想我可以使用直接调用Labels控制器来检索标签,但我想更多地将它视为具有所有maint的常量。它提供的优势。

    从外部源初始化常量的正确(推荐)方法是什么,例如plist?希望你能帮忙,我已经失去了几个小时试图解决这个问题!

    提前谢谢。

4 个答案:

答案 0 :(得分:1)

如果从plist文件初始化,则没有常量。你不应该这样定义它。

我猜你想要的是能够将这个值视为一个常量吗?而这可以通过延迟初始化来实现。

NSString* AlertQuitTitle() 
{
    static NSString* title = nil;
    if (title == nil) 
    {
        LabelsController* labels = [LabelsController instance];     
        title = labels.alertQuitTitle;           
    }
    return title;
}

为什么不使用NSLocalizedString()宏来获取警报退出标题,有充分的理由吗?

警告

如警告所示,您正在自动发布池之外执行+ load方法。这意味着所有对autorelease的调用只是泄漏内存。您可以像这样修复您的方法:

+ (void)load 
{
    // this controller contains all the strings retrieved from the plist file
    NSAutoreleasePool* pool = [NSAutoreleasePool new];
    LabelsController *labels = [LabelsController instance];     
    ALERT_QUIT_TITLE = labels.alertQuitTitle;
    [pool release];
}

答案 1 :(得分:0)

我建议使用NSUserDefaults方法来存储数据。

答案 2 :(得分:0)

为了大多数目的,在过程中过早地调用负载。即使初始化也相当早。正如您所指出的那样,没有自动释放池设置,因此任何使用它(这很难避免)都会给您警告和可能的泄漏。

更好的方法是完全忘记常量,并编写LabelController alertQuitTitle来懒惰地初始化其数据库并缓存其答案。这样的事情(未经测试,未编译)。

+ (NSDictionary*) labelStrings;
{
    static NSDictionary* strings = nil;
    if ( !strings ) {
        // Allocate and laod and keep ownership of the NSDictionary
    }
    return strings;
}

+ (NSString*) alertQuitTitle
{
    static NSString* alertQuitTitle = nil;
    if ( !alertQuitTitle ) {
        alertQuitTitle = [[LabelController strings] objectForKey:@"alertQuitTitle"];
    }
    return alertQuitTitle;
}

如果您真的想要,可以将alertQuitTitle转换为宏,并使用它轻松创建数十种方法。

在你的其他代码中,如果你真的想要,你可以编写一个缓存答案的方法,但那没有用,只需使用[LabelController alertQuitTitle]。

如果您愿意,可以使用单例,但是除非您还有其他事情要做,否则创建LabelController的单个实例并没有什么意义 - 它需要的任何数据都可以存储为静态变量。然而,单身人士会更加符合典型的Cocoa行为。无论哪种方式,相同的技术都可以。

答案 3 :(得分:0)

要直接回答您的问题,看起来您在设置NSAutoreleasePool之前正在调用load。每个线程都需要自己的NSAutoreleasePool;您的主线程的NSAutoreleasePool在main.m中设置,如果您打开该源文件,可以看到。

我通常在App Delegate的init方法中初始化我的应用程序的全局变量。

但这看起来像是不必要的优化,因此会产生问题。你应该考虑使用字符串资源来做这样的事情。请参阅NSBundle localizedStringForKey:value:table:NSLocalizedString()