从 plist 初始化 Objective-C 字符串常量
我已经使用 '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
使用日志调用我可以验证加载代码是否被提前调用在应用程序启动时,甚至在 AppDelegate 构造函数之前。然而,我认为这种方法有两件事不好:
- 我必须删除“const”关键字,否则我会收到编译错误,因为我试图初始化一个定义为常量的变量,
- 我会收到某种关于自动释放池:
*** _NSAutoreleaseNoPool():类 NSPathStore2 的对象 0x50b330 自动释放,没有池 - 只是泄漏 堆栈:(0x905caf0f 0x904d8647 0x904e039f(等)
我想我可以使用直接调用标签控制器来检索标签,但我更希望将其视为具有所有维护功能的常量。它提供的优点。
这将是从外部源初始化常量的正确(推荐)方法,例如本例中的 plist?希望您能提供帮助,我已经花了好几个小时来尝试解决此问题
!
I have defined a constants class within my iphone program using the 'extern' and 'const' keywords as in the example described in:
At this point, I am trying to initialize some string constants from the contents of a plist file, instead of being defined right in the class, e.g., instead of having:
// Constants.m
NSString * const MyConstant = @"a constant";
I would like to have it initialized somewhere from the plist file. So far, I have done a test using the static +(void)load
method, but I am not completely happy about it, e.g.:
// 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
Using a log call I can verify that the load code gets called early in the app startup, even before the AppDelegate constructor. However, two things I see not good in this approach:
- I have to remove the 'const' keyword, otherwise I get a compile error since I am trying to initialize a variable that is defined as constant
- I get some sort of warning message about the autoreleased pool:
*** _NSAutoreleaseNoPool(): Object 0x50b330 of class NSPathStore2 autoreleased with no pool in place - just leaking
Stack: (0x905caf0f 0x904d8647 0x904e039f (etc)
I guess I could use a direct call to the Labels controller to retrieve the label, but I would like more to treat it like a constant having all the maint. advantages it provides.
Which would be the correct (recommended) way to initialize a constant from an external source, like in this case a plist? Hope you can help, I have lost a good few hours trying to resolve this!
Thank you in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果从 plist 文件初始化,则没有常量。而且你不应该这样定义它。
我猜你想要的是能够将这个值视为一个常数?这可以通过使用延迟初始化来实现。
是否有充分的理由说明为什么不使用 NSLocalizedString() 宏来获取警报退出标题?
警告
正如警告所述,您正在自动释放池之外执行 +load 方法。这意味着所有对 autorelease 的调用都会泄漏内存。您可以像这样修复您的方法:
If you initialize from a plist file, then you do not have a constant. And you should not define it as such.
I am guessing what you want is to be able to treat this value as if it was a constant? And that can be achieved using lazy initialization instead.
Is there a good reason as to why you do not use the NSLocalizedString() macro to fetch the alert quit title?
The warning
As the warning states, you are executing the +load method outside of an auto release pool. Meaning that all calls to autorelease just leak memory. You can fix your method like this:
我建议使用 NSUserDefaults 方法来存储数据。
I would suggest using the NSUserDefaults method instead for storing data.
对于大多数目的来说,在该过程中调用 Load 太早了。甚至初始化也相当早。正如您所指出的,没有自动释放池设置,因此任何使用它(这是很难避免的)都会给您警告和可能的泄漏。
更好的方法是完全忘记常量,并编写 LabelControlleralertQuitTitle 来延迟初始化其数据库并缓存其答案。像这样的东西(未经测试,未编译)。
如果您确实愿意,可以将alertQuitTitle 转换为宏并使用它轻松创建数十种方法。
在您的其他代码中,如果您确实愿意,您也可以编写一个缓存答案的方法,但这毫无意义,只需使用 [LabelControlleralertQuitTitle]。
如果您愿意,可以使用单例,但是即使创建 LabelController 的单个实例也没有多大意义,除非您有其他事情要做 - 它需要的任何数据都可以存储为静态变量。不过,单例更符合典型的可可行为。无论哪种方式,相同的技术都会起作用。
Load is called far too early in the process for most purposes. Even initialize is fairly early. As you've noted, there is no autorelease pool setup, so any use of it (which is quite hard to avoid) will give you warnings and possible leaks.
A better way to do it is to forget the constant entirely, and write LabelController alertQuitTitle to lazily initialize its database and cache its answer. Something like this (untested, uncompiled).
If you really want, you can convert alertQuitTitle into a macro and use that to easily create dozens of methods.
In your other code, if you really want to, you can write a method that caches the answer as well, but thats fairly pointless, instead just use [LabelController alertQuitTitle].
You can, if you prefer, use a singleton, but there is not much point even creating a single instance of LabelController unless you have other things for it to do - any data it needs can be stored as static variables. A singleton would be more inline with typical Cocoa behaviour though. Either way, the same technique will work.
要直接回答您的问题,您似乎在设置 NSAutoreleasePool 之前调用
load
。每个线程都需要自己的 NSAutoreleasePool;你的主线程的 NSAutoreleasePool 在main.m
中设置,如果你打开该源文件,你可以看到它。我通常在应用程序委托的
init
方法中初始化应用程序的全局变量。但这看起来像是不必要的优化,并且因此产生了问题。您应该考虑使用字符串资源来实现类似的目的。请参阅 NSBundle localizedStringForKey:value:table: 和 NSLocalizedString()
To directly answer your question, it looks like you're calling
load
before an NSAutoreleasePool has been set up. Every thread needs its own NSAutoreleasePool; your main thread's NSAutoreleasePool is set up inmain.m
, which you can see if you open up that source file.I usually initialize my application's globals in my App Delegate's
init
method.But this looks like unnecessary optimization, and it's creating problems as a result. You should consider using string resources for something like this. See
NSBundle localizedStringForKey:value:table:
, andNSLocalizedString()