Когда использовать статическую строку против #define - PullRequest
45 голосов
/ 19 января 2010

Я немного смущен тем, когда лучше использовать:

static NSString *AppQuitGracefullyKey = @"AppQuitGracefully";

вместо

#define AppQuitGracefullyKey    @"AppQuitGracefully"

Я видел такие вопросы для C или C ++, и я думаю, что здесь все по-другому, это то, что это специально для Objective C, использующего объект, и на устройстве, таком как iPhone, может быть стек, код или проблемы с памятью, которые я еще не понимаю.

Одно использование будет:

appQuitGracefully =  [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];

Или это просто вопрос стиля?

Спасибо.

Ответы [ 6 ]

60 голосов
/ 19 января 2010

Если вы используете static, компилятор вставит ровно одну копию строки в ваш двоичный файл и просто передаст указатели на эту строку, что приведет к более компактным двоичным файлам. Если вы используете #define, при каждом использовании будет отдельная копия строки, хранящейся в источнике. Постоянное объединение строк справится со многими проблемами, но вы заставляете компоновщик работать без всякой причины.

14 голосов
/ 19 января 2010

См. "static const" vs "#define" vs "enum" .Основным преимуществом static является безопасность типов.

Кроме этого, подход #define обеспечивает гибкость конкатенации строк, которая не может быть выполнена со статическими переменными, например

#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:ROOT_PATH@"/UIKit.framework"] load];

но это, вероятно, не очень хороший стиль:).

4 голосов
/ 02 июля 2015

Я бы на самом деле не рекомендовал ни одного, вместо этого вы должны использовать extern. Objective-c уже определяет FOUNDATION_EXPORT, что на более переносимо , чем extern, поэтому глобальный NSString экземпляр будет выглядеть примерно так:

.h

FOUNDATION_EXPORT NSString * const AppQuitGracefullyKey;

.m

NSString * const AppQuitGracefullyKey = @"AppQuitGracefully";

Я обычно помещаю их в файлы объявлений (например, MyProjectDecl.h) и импортирую всякий раз, когда мне нужно.

Есть несколько различий в этих подходах:

  • # define имеет несколько недостатков, таких как небезопасность типа. Это правда, что для этого есть обходные пути (например, #define ((int)1)), но какой в ​​этом смысл? И кроме того, у этого подхода есть недостатки отладки. Компиляторы предпочитают константы. См. это обсуждение.
  • статические глобалы видны в объявленном файле.
  • extern делает переменную видимой для всех файлов. Это контрастирует со статическим.

Статические и внешние отличаются видимостью. Также примечательно, что ни один из этих подходов не дублирует строку (даже #define), поскольку компилятор использует String Interning для предотвращения этого. В этом посте NSHipster они показывают доказательство:

NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES

Оператор == возвращает YES, только если две переменные указывают на один и тот же экземпляр. И, как вы можете видеть, это так.

Вывод: используйте FOUNDATION_EXPORT для глобальных констант. Он удобен для отладки и будет виден во всем вашем проекте.

4 голосов
/ 16 октября 2012

После некоторого поиска ( этот вопрос / ответ среди прочего) я думаю, что важно сказать, что в любое время, когда вы используете строковый литерал @"AppQuitGracefully", создается постоянная строка, независимо от того, сколько раз вы используете его, он будет указывать на тот же объект.

Поэтому я думаю (и извиняюсь, если ошибаюсь), что это предложение в ответе выше неверно: If you use a #define, there will be a separate copy of the string stored in the source on each use.

3 голосов
/ 17 декабря 2014

ИСПОЛЬЗОВАНИЕ #define:

вы не можете отладить значение идентификатора

работа с #define и другими макросами - это задание Pre-Processor, когдасначала вы нажимаете Build / Run, он предварительно обработает исходный код, он будет работать со всеми макросами (начиная с символа #),

Предположим, вы создали

#define LanguageTypeEnglish @"en"

и использовалиэто в 2 местах в вашем коде.

NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;

он заменит "LanguageTypeEnglish" на @"en" во всех местах.Таким образом, будут созданы 2 копии @"en".то есть

NSString *language = @"en";
NSString *languageCode = @"en";

Помните, что до этого процесса компилятор не отображается.

После предварительной обработки всех макросов на экране появляется компилятор, и он получает код ввода, подобный этому,

NSString *language = @"en";
NSString *languageCode = @"en";

и скомпилируйте его.

ИСПОЛЬЗУЯ статический:

он учитывает область видимости и является типобезопасным.вы можете отладить значение идентификатора

Во время процесса компиляции, если найден компилятор,

static NSString *LanguageTypeRussian = @"ru";

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

Таким образом, используя статические, в пределах одного генерируется только одна копия переменнойсфера.

3 голосов
/ 19 января 2010

Я использую static, когда мне нужно экспортировать символы NSString из библиотеки или фреймворка. Я использую #define, когда мне нужна строка во многих местах, которую я могу легко изменить. В любом случае, компилятор и компоновщик позаботятся об оптимизации.

...