статическое использование NSString и встроенные константы NSString - PullRequest
42 голосов
/ 21 декабря 2009

В 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 *? Или я что-то упустил?

Ответы [ 6 ]

58 голосов
/ 21 декабря 2009

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

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

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

36 голосов
/ 03 декабря 2012

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

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

extern NSString *const MyTypoProneString;

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

NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";

При этом ... если вы просто хотите static const, ЛОКАЛЬНЫЙ для реализации вашего класса ( или даже определенный метод! ) ... просто объявите string INSIDE реализация (или метод) как ...

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

РЕДАКТИРОВАТЬ Хотя я действительно показываю, как это сделать ... Мне еще предстоит убедиться, что этот стиль в любом случае лучше , чем до смешного короче, проще и менее повторяющееся ОДНО декларация, как все ..

#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots"

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

9 голосов
/ 21 декабря 2009

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

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

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

3 голосов
/ 21 декабря 2009

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

2 голосов
/ 21 декабря 2009

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

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

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

#define kCellId @"CellId"

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

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

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

1 голос
/ 25 февраля 2014

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...