Как я могу использовать NSArray как глобальную константу?

Я использую набор файлов Constant.m, по одному на цель, для определения конкретных вещей для каждой цели. Например:

// Constants.h
extern NSString * const kDatabaseFileName;
//Constants.m
NSString * const kDatabaseFileName = @"target_one.sqlite";

Я также хотел бы определить NSArray для каждой из моих целей:

NSArray * const kLabelNames = [[NSArray alloc] initWithObjects:
    @"nameLabel", @"addressLabel", nil];

Но это дает "ошибка: элемент инициализации не является константой". Использование 'arrayWithObjects` также не работает. Это потому, что строки в моем массиве не являются константами?

Как настроить массив как глобальную константу? Спасибо.

Ответ 1

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

У вас может быть один файл заголовка и несколько файлов реализации (по одному на цель). Пока все реализуют класс, объявленный в файле заголовка, вы должны быть в порядке.

Ответ 2

В Objective-C объекты могут быть выделены только в куче, поэтому нет способа создать NSArray в статической памяти. Однако вы можете создать массив C указателей для констант NSString, например...

NSString * const kLabelNames[] = {
    @"Foo", @"Bar", @"Baz"
};

... и затем вы можете написать методы класса, подобные этому...

+ (NSArray *)labelNames
{
    static NSArray *names;
    if (names == nil) {
        names = [[NSArray alloc] initWithObjects:kLabelNames count:3];
    }
    return names;
}

Edit

Обратите внимание, что с внедрением новых технологий, таких как ARC, Grand Central Dispatch и нового синтаксиса литералов для массивов, теперь есть более простой способ добиться чего-то подобного. Обратите внимание, что приведенный ниже пример также обеспечивает большую безопасность потоков, хотя исходный пример мог бы включить блок @synchronized или один из нескольких других механизмов для достижения аналогичных результатов.

+ (NSArray *)labelNames
{
    static NSArray *names;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        names = @[@"Foo", @"Bar", @"Baz"];
    });

    return names;
}

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

NSString * const kLabelNames[] = {
    @"Foo", @"Bar", @"Baz"
};

+ (NSArray *)labelNames
{
    static NSArray *names;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        names = [NSArray arrayWithObjects:kLabelNames count:3];
    });

    return names;
}

Ответ 3

Здесь гораздо более простой подход:

Объявить NSString с помощью элементов, разделенных запятыми (или любого другого разделителя)

NSString *const kLabelNames = @"Foo,Bar,Baz";

Затем конвертируйте в NSArray всякий раз, когда вам это нужно:

NSArray *namesArray = [kLabelNames componentsSeparatedByString:@","];

Ответ 4

Используйте макрос:

#define SOME_ARRAY (@[@"blah", @"asdf", @"qwerty"])

Ответ 5

Вам следует создать класс, содержащий константы в методах класса. Затем вы можете добавить класс к любой цели и вызвать методы для получения констант в таких объектах, как массивы. Замените класс или реализацию класса, чтобы изменить возврат констант.

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

Ответ 6

Если вы хотите избежать проверки NULL при каждом использовании, вы можете подклассифицировать метод NSObject + initialize. Это будет вызвано один раз, при первом создании экземпляра класса (и еще раз для каждого подкласса, если будут созданы какие-либо подклассы), и это очень хорошее место для этой инициализации.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html%23//apple_ref/occ/clm/NSObject/initialize