我使用'extern'和'const'关键字在我的iphone程序中定义了一个常量类,如下所示:
此时,我试图从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构造函数之前。但是,我认为这种方法有两件事情不太好:
*** _NSAutoreleaseNoPool():类NSPathStore2的对象0x50b330自动释放,没有池到位 - 只是泄漏 堆栈:(0x905caf0f 0x904d8647 0x904e039f(etc)
我想我可以使用直接调用Labels控制器来检索标签,但我想更多地将它视为具有所有maint的常量。它提供的优势。
从外部源初始化常量的正确(推荐)方法是什么,例如plist?希望你能帮忙,我已经失去了几个小时试图解决这个问题!
提前谢谢。
答案 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()