Когда использовать статическую строку vs. #define
Я немного смущен, когда лучше всего использовать:
static NSString *AppQuitGracefullyKey = @"AppQuitGracefully";
вместо
#define AppQuitGracefullyKey @"AppQuitGracefully"
Я видел такие вопросы, как это для C или С++, и я думаю, что здесь различно то, что это специально для Objective C, используя объект, а на устройстве, таком как iPhone, может быть стек, кодовое пространство или которые я еще не понимаю.
Одно использование:
appQuitGracefully = [[NSUserDefaults standardUserDefaults] integerForKey: AppQuitGracefullyKey];
Или это просто вопрос стиля?
Спасибо.
Ответы
Ответ 1
Если вы используете статический код, компилятор будет вставлять ровно одну копию строки в ваши двоичные и простые указатели на эту строку, что приведет к созданию более компактных двоичных файлов. Если вы используете #define, при каждом использовании будет существовать отдельная копия строки, хранящейся в источнике. Постоянная коалесценция будет обрабатывать многие из дублирующих устройств, но вы делаете компоновщик работать без усилий.
Ответ 2
См. "static const" vs "# define" vs "перечисление" . Основным преимуществом static
является безопасность типов.
Кроме того, подход #define
представляет гибкость встроенной конкатенации строк, которая не может быть выполнена со статическими переменными, например.
#define ROOT_PATH @"/System/Library/Frameworks"
[[NSBundle bundleWithPath:[email protected]"/UIKit.framework"] load];
но это, вероятно, не очень хороший стиль:).
Ответ 3
После некоторого поиска (этого вопроса/ответа, среди прочего), я думаю, важно сказать, что в любое время, когда вы используете строковый литерал @"AppQuitGracefully"
константа string и независимо от того, сколько раз вы его используете, он укажет на тот же объект.
Итак, я думаю (и извиняюсь, если ошибаюсь), что это предложение в правильном ответе неверно: If you use a #define, there will be a separate copy of the string stored in the source on each use.
Ответ 4
Я бы не рекомендовал ни того, что вы должны использовать 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
для глобальных констант. Он отлаживает дружеские отношения и будет виден всем вашим проектом.
Ответ 5
Я использую static
, когда мне нужно экспортировать символы NSString из библиотеки или рамки. Я использую #define
, когда мне нужна строка во многих местах, которые я могу легко изменить. Во всяком случае, компилятор и компоновщик позаботятся об оптимизации.
Ответ 6
ИСПОЛЬЗОВАНИЕ #define:
вы не можете отлаживать значение идентификатора
Работа С#define и другими макросами - это задание Pre-Processor,
Когда вы сначала нажмете Build/Run, он будет обрабатывать исходный код, он будет работать со всеми макросами (начиная с символа #),
Предположим, вы создали,
#define LanguageTypeEnglish @"en"
и использовал это в двух местах в вашем коде.
NSString *language = LanguageTypeEnglish;
NSString *languageCode = LanguageTypeEnglish;
он заменит "LanguageTypeEnglish" на @"en"
во всех местах.
Таким образом, будут созданы 2 копии @"en"
.
iee
NSString *language = @"en";
NSString *languageCode = @"en";
Помните, что до этого процесса компилятор не находится на картинке.
После предварительной обработки всех макросов, компилятор входит в изображение, и он получит код ввода, подобный этому,
NSString *language = @"en";
NSString *languageCode = @"en";
и скомпилируйте его.
ИСПОЛЬЗОВАНИЕ static:
он уважает область действия и безопасен по типу.
вы можете отлаживать значение идентификатора
В процессе компиляции, если найден компилятор,
static NSString *LanguageTypeRussian = @"ru";
то он проверяет, была ли ранее сохранена переменная с тем же именем,
если да, то он будет передавать указатель этой переменной,
если нет, он создаст эту переменную и передаст ее указателю, в следующий раз он будет передавать только указатель того же самого.
Таким образом, используя static, в пределах области создается только одна копия переменной.