Инициализировать строковые константы Objective-C из plist - PullRequest
0 голосов
/ 29 августа 2009

Я определил класс констант в моей программе для iphone, используя ключевые слова 'extern' и 'const', как в примере, описанном в:

Константы в 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 (): объект 0x50b330 класса NSPathStore2 автоматически освобожден без пула - только утечка Стек: (0x905caf0f 0x904d8647 0x904e039f (и т. Д.)

Полагаю, я мог бы использовать прямой вызов контроллера Labels для извлечения метки, но я бы хотел больше относиться к нему как к константе, имеющей все свойства. преимущества это обеспечивает.

Какой будет правильный (рекомендуемый) способ инициализации константы из внешнего источника, как в этом случае plist? Надеюсь, вы можете помочь, я потерял несколько часов, пытаясь решить эту проблему!

Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 29 августа 2009

Если вы инициализируете из файла plist, то у вас нет константы. И вы не должны определять это как таковое.

Я предполагаю, что вы хотите, чтобы иметь возможность обрабатывать это значение, как если бы оно было константой? И этого можно достичь, используя вместо этого ленивую инициализацию.

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

Есть ли веская причина, по которой вы не используете макрос NSLocalizedString () для получения заголовка о выходе из оповещения?

Предупреждение

Как указывается в предупреждении, вы выполняете метод + load вне пула автоматического выпуска. Это означает, что все вызовы авто-релиза просто пропускают память. Вы можете исправить свой метод так:

+ (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];
}
0 голосов
/ 29 августа 2009

Чтобы прямо ответить на ваш вопрос, похоже, что вы звоните load до того, как NSAutoreleasePool был настроен. Каждый поток нуждается в своем собственном NSAutoreleasePool; NSAutoreleasePool вашего основного потока настроен в main.m, что вы можете увидеть, если откроете этот исходный файл.

Обычно я инициализирую глобальные переменные моего приложения в методе моего делегата приложения init.

Но это выглядит как ненужная оптимизация, и в результате возникают проблемы. Вы должны рассмотреть возможность использования строковых ресурсов для чего-то подобного. См NSBundle localizedStringForKey:value:table: и NSLocalizedString()

0 голосов
/ 29 августа 2009

Загрузка вызывается слишком рано для большинства целей. Даже инициализировать довольно рано. Как вы заметили, настройка пула автоматического выпуска отсутствует, поэтому любое его использование (которого довольно сложно избежать) выдаст вам предупреждения и возможные утечки.

Лучший способ сделать это - полностью забыть константу и написать 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, если у вас нет других дел - любые необходимые данные могут храниться как статические переменные. Синглтон был бы более встроен в типичное поведение Какао. В любом случае, будет работать та же техника.

0 голосов
/ 29 августа 2009

Я бы предложил использовать метод NSUserDefaults вместо хранения данных.

...