Как мне объявить массив как константу в Objective-c? - PullRequest
63 голосов
/ 13 марта 2010

Следующий код дает мне ошибки:

//  constants.h
extern NSArray const *testArray;
//  constants.m
NSArray const *testArray = [NSArray arrayWithObjects:  @"foo", @"bar", nil];

Я получаю ошибку
initializer element is not constant

Или, если я уберу указатель (*), я получу:
statically allocated instance of Objective-C class 'NSArray'

Ответы [ 6 ]

69 голосов
/ 13 марта 2010

Короче, ты не можешь.Объекты Objective-C, за исключением констант NSString, создаются только во время выполнения, и поэтому вы не можете использовать выражение для их инициализации.

Существует несколько подходов.

(1) Объявите NSArray *testArray без ключевого слова const, а затем получите код, который устанавливает значение, которое вызывается очень рано в течение жизненного цикла приложения.

(2) Объявите удобный метод классакоторый возвращает массив, затем используйте static NSArray *myArray в этом методе и рассматривайте его как одноэлементный (ищите SO по запросу "target-c singleton", чтобы найти около миллиона ответов о том, как создать экземпляр).

33 голосов
/ 14 июля 2012

Немного опоздал на вечеринку, но так как вы не изменяете значения в ходе программы, если бы вы имели дело только со строками, вы могли бы сделать следующее, объявив свой массив с помощью массива C:

extern NSString * const MY_CONSTANT_STRING_ARRAY[];

в вашем constants.h файле, а затем в constants.m вы можете добавить к нему объекты следующим образом:

NSString * const MY_CONSTANT_STRING_ARRAY[] = { @"foo", @"bar" };

Затем, чтобы получить доступ к члену, вы можете сделать цикл for таким же образом с помощью оператора C sizeof():

Это, очевидно, массив C, а не NSArray, поэтому к нему не прикрепляются все забавные методы, такие как objectAtIndex:, поэтому вы можете создать вспомогательную функцию где-нибудь в вашей программе, которая проходит по циклу все строки, используя метод, который я описал выше, и возвращает NSArray (или NSMutableArray четный). Но если вы делали то, что я есть, и вам просто нужен постоянный массив значений NSString для использования в вашей программе, этот метод работает лучше всего.

Делая это таким образом, вы инкапсулируете все ваши константы строкового массива в constants.h и по-прежнему доступны в вашей программе, добавив constants.h в ваш файл .pch вместо создания синглтона только для этого массива значений или настроек массив с небольшим кодом, который как бы побеждает назначение файла constants, потому что он удаляет фактические константы из файла constants ..

РЕДАКТИРОВАТЬ за @ JesseGumpo's Comment :

Поскольку могут возникнуть проблемы с использованием sizeof() для определения размера массива, простой обходной путь - объявить размер массива в файле констант следующим образом:

//.h
extern int SIZE_OF_MY_CONSTANTS_ARRAY;  

///.m
int SIZE_OF_MY_CONSTANTS_ARRAY = 2;

А затем для доступа к членам цикла for вы можете сделать это следующим образом:

for (int i=0; i < SIZE_OF_MY_CONSTANTS_ARRAY; i++) 
        NSLog(@"my constant string is: %@", MY_CONSTANT_STRING_ARRAY[i]);

Да, это не динамически фиксирует размер массива, но если вы объявляете массив в файле констант, вы уже знаете размер этого массива с самого начала, так что, хотя он добавляет еще две строки код, он по-прежнему решает задачу наличия массива в файле констант.

Если у кого-то есть еще предложения или могут быть известны другие C трюки, оставьте комментарий ниже!

9 голосов
/ 08 мая 2014

Вот макрос, который делает это в одной строке для статического экземпляра в области видимости метода.

#define STATIC_ARRAY(x, ...)   \
        static NSArray* x=nil; \
        static dispatch_once_t x##onceToken; \
        dispatch_once(&x##onceToken, ^{ x = @[ __VA_ARGS__ ]; });

Пример использования

    STATIC_ARRAY(foo, @"thing1", @"thing2", [NSObject new]);
6 голосов
/ 15 января 2015

Для меня удобнее использовать следующую реализацию для массива констант

static NSString * kHeaderTitles [3] = {@ "ACCOUNT DETAILS", @ "SOCIAL NETWORK", @ "SETTINGS"};
static int kNumbers[3] = {1, 2, 3};
6 голосов
/ 08 июня 2011

Это довольно просто:

#define arrayTitle [NSArray arrayWithObjects: @"hi",@"foo",nil]

ставить перед реализацией и без точки с запятой.

надеюсь, это поможет.

3 голосов
/ 07 апреля 2015

У меня есть заголовочный файл с именем "Constants.h" и в следующих постоянных массивах:

#define arrayOfStrings @[@"1", @"2", @"3", @"4"]
#define arraysOfIds @[@(1), @(2), @(3), @(4)]

Обычно, когда вы вызываете arrayOfStrings в вашем коде, он заменяется на @ [@ "1", @ "2", @ "3", @ "4"] и то же самое с arraysOfIds.

...