【问题标题】:Initialize Objective-C string constants from plist从 plist 初始化 Objective-C 字符串常量
【发布时间】:2009-08-28 20:32:34
【问题描述】:

我已经在我的 iphone 程序中使用“extern”和“const”关键字定义了一个常量类,如以下示例中所述:

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

使用日志调用,我可以验证加载代码是否在应用启动的早期被调用,甚至在 AppDelegate 构造函数之前。但是,我认为这种方法有两点不好:

  1. 我必须删除 'const' 关键字,否则我会收到编译错误,因为我试图初始化一个定义为常量的变量
  2. 我收到一些关于自动释放池的警告消息:

*** _NSAutoreleaseNoPool(): NSPathStore2 类的对象 0x50b330 自动释放,没有适当的池 - 只是泄漏 堆栈:(0x905caf0f 0x904d8647 0x904e039f(等)

我想我可以使用直接调用 Labels 控制器来检索标签,但我更希望将其视为具有所有维护功能的常量。它提供的优势。

哪种方法是从外部源初始化常量的正确(推荐)方法,例如在本例中为 plist?希望您能提供帮助,我已经浪费了好几个小时试图解决这个问题!

提前谢谢你。

【问题讨论】:

    标签: iphone objective-c constants


    【解决方案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];
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        一个更好的方法是完全忘记这个常量,并编写 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 行为。无论哪种方式,相同的技术都会起作用。

        【讨论】:

          【解决方案4】:

          为了直接回答您的问题,您似乎在设置 NSAutoreleasePool 之前调用了load。每个线程都需要自己的 NSAutoreleasePool;你的主线程的 NSAutoreleasePool 设置在main.m,如果你打开那个源文件就可以看到。

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

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

          【讨论】:

            猜你喜欢
            • 2019-06-17
            • 1970-01-01
            • 1970-01-01
            • 2021-05-25
            • 2013-03-25
            • 2020-04-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多