Подтвердить что ты не робот

Статическое использование NSString против встроенных констант NSString

В Objective-C я понимаю, что директива @ "foo" определяет константу NSString. Если я использую @ "foo" в нескольких местах, ссылается на тот же неизменный объект NSString.

Почему я так часто вижу этот фрагмент кода (например, в повторном использовании UITableViewCell):

static NSString *CellId = @"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellId];

Вместо просто:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId"];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"CellId"];

Я предполагаю, что это защитит меня от создания опечатки в имени идентификатора, который компилятор не поймал. Но если так, я не могу просто:

#define kCellId @"CellId"

и избежать статического бит NSString *? Или я что-то упускаю?

4b9b3361

Ответ 1

Хорошая практика превращать литералы в константы, потому что:

  • Это помогает избежать опечаток, как вы сказали
  • Если вы хотите изменить константу, вам нужно изменить ее только в одном месте.

Я предпочитаю использовать static const NSString* static NSString* const, потому что он немного безопаснее, чем #define. Я стараюсь избегать препроцессора, если я действительно не нуждаюсь в нем.

Ответ 2

Мне нравятся все ответы здесь без простого примера того, как правильно объявить один... так...

Если вы хотите, чтобы константа была внешне видимой (т.е. "глобальная" ).... объявляйте ее как таковой в заголовке...

extern NSString *const MyTypoProneString;

и определите его в файле .m, ВНЕШНИЙ любой @implementation, как...

NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";

Тем не менее, если вы просто хотите static const, чтобы ЯВЛЯЕТСЯ ЛОКАЛЬНЫМ для реализации вашего класса (или даже определенного метода!)... просто объявите строку INSIDE реализация (или метод) как...

static NSString *MavisBeacon = @"She a freakin' idiot";

EDIT Хотя я и показываю, как это сделать... Я еще не убежден, что этот стиль ничуть лучше, чем смехотворно более короткое, более простое и менее повторяющееся объявление SINGLE, ла..

#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots"

Используйте #define... они намного менее раздражают. Просто не позволяйте препроцессорным игрокам ненавидеть вас.

Ответ 3

Вы должны сделать статическую переменную const.

Одно отличие между статической переменной и макросом заключается в том, что макросы плохо работают с отладчиками. Макросы также не относятся к типу.

Большая часть рекомендаций static-var-vs-macro для C и С++ применима к Obj-C.

Ответ 4

Не гарантируется, что при использовании @"foo" в нескольких местах среда выполнения использует для них одно и то же хранилище и, конечно же, может не иметь места в пределах блока компиляции или границ библиотеки.
Я предпочел бы использовать static NSString *string = @"foo", особенно с большим количеством литералов.

Ответ 5

Я предполагаю, что это защитит меня от создания опечатки в имени идентификатора, который компилятор не поймал.

Правильно. Это просто базовая защитная практика программирования. Скомпилированный результат (надеюсь) одинаковый в любом случае.

Но если так, я не могу просто:

#define kCellId @"CellId"

и избежать статического бит NSString *? Или я что-то упускаю?

Да. Но символ kCellId будет определяться глобально, по крайней мере, в вашем блоке компиляции. Объявление статической переменной делает символ локальным для этого блока.

Обычно вы увидите строковые константы, определяемые как глобальные переменные или статические переменные, а не препроцессор. Это помогает убедиться, что вы используете только один экземпляр строки между разными единицами компиляции.

Ответ 6

Итак, я займусь этим немного позже, но это было задано много раз по-разному в обеих областях C/С++ SO, но в основном здесь расширенная версия моего комментария для alex gray:

В любое время, когда вы думаете, что вы должны использовать #define для строковых макросов, вы, скорее всего, не должны. Причина в том, что макросы #define в основном заменяют регулярные выражения на препроцессор. Каждый раз, когда препроцессор видит макрос, он заменяет его тем, что вы определили. Это означает, что новый строковый литерал каждый раз будет выделен в память, что очень плохо в таких местах, как идентификаторы повторного использования ячеек (поэтому код Apple UITableViewController по умолчанию использует статический).

Использование extern/static const вместо этого указывает все ссылки на одно место в памяти, как упоминал Эниль. Это намного эффективнее и эффективнее для памяти, что очень важно для мобильных устройств.