Глобальные переменные в какао / Objective-C? - PullRequest
19 голосов
/ 03 декабря 2008

Согласно Программирование какао для Mac OS X, 3-е издание, на стр. 202 (глава 13):

Вы будете регистрироваться, читать и установка значений по умолчанию в нескольких классах в ваше приложение. Чтобы убедиться, что вы всегда используете одно и то же имя, вы следует объявить эти строки в один файл, а затем просто #import этот файл в любой файл, в котором вы используйте имена. Есть несколько способов сделать это. Например, вы можете использовать команда препроцессора C #define, но большинство программистов Какао используют глобальные переменные для этой цели.

Это действительно правильная лучшая практика? Глобальные переменные? Это кажется мне безумным - вопреки всему, чему меня учили.

Будет ли лучший дизайн простым классом Singleton с этими определениями? Или это действительно правильная лучшая практика для выхода на мировой рынок? Есть ли лучший образец, чем любой, учитывая, что многие люди считают синглтоны глобалами в красивом платье?

Ответы [ 7 ]

63 голосов
/ 04 декабря 2008

Просто чтобы прояснить, рекомендуется создать неизменные глобальные переменные вместо встроенных строковых констант (трудно реорганизовать и без проверки во время компиляции) или #defines (без проверки во время компиляции) , Вот как вы можете это сделать ...

в MyConstants.h:

extern NSString * const MyStringConstant;

в MyConstants.m:

NSString * const MyStringConstant = @"MyString";

затем в любом другом файле .m:

#import "MyConstants.h"

...
[someObject someMethodTakingAString:MyStringConstant];
...

Таким образом, вы получаете проверку во время компиляции, что вы не ошиблись в написании строковой константы, вы можете проверить равенство указателей, а не равенство строк [1] ​​при сравнении ваших констант, и отладка проще, поскольку константы имеют строковое значение времени выполнения.

[1] В этом случае вы по существу используете значения указателя в качестве констант. Так уж получилось, что эти конкретные целые числа также указывают на строки, которые можно использовать в отладчике

18 голосов
/ 04 декабря 2008

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

Это глобальная константа - глобальная по объему, но постоянная и, следовательно, неплохая в том смысле, что глобальные переменные плохие.

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

  • Каждый класс в вашей программе
  • Каждый # определяет
  • Каждое перечисление
  • Почти каждое имя, объявленное Cocoa (за исключением редких глобальных переменных, таких как NSApp).

Единственный раз, когда вам следует беспокоиться о глобальных константах, это когда их имена слишком общие (они могут загрязнять глобальное пространство имен). Поэтому не используйте имена, которые могут конфликтовать с чем-либо (всегда используйте префикс и всегда ставьте имя для конкретной задачи, например NSKeyValueObservingOptionNew).

18 голосов
/ 03 декабря 2008

Глобальные переменные или синглтон будут выполнять то же самое здесь. И то, и другое можно использовать, чтобы превратить «ключевые» имена в Какао, которые не приведут к ошибке компилятора, если они ошибочно написаны в ошибке компилятора. Это основная цель. Глобальные переменные немного проще, хотя, видя их, требуют меньше ввода.

Вместо этого:

[myArray setObject:theObject forKey:MyGlobalVariableKeyName];

Вы должны сделать что-то вроде:

[myArray setObject:theObject 
            forKey:[[MySingletonVariableClass getInstance] myVariableKeyName];

Глобальные переменные существенно меньше набирают для того же эффекта.

3 голосов
/ 03 декабря 2008

Постоянные глобальные переменные, которые устанавливаются во время компиляции и никогда не меняются, являются приемлемыми для меня. Если вы жестко кодируете строку, это то же самое, просто скрытое компилятором. Я буду избегать изменчивых глобалов, таких как чума.

Помните, что Apple сама использует ту же технику. Многие из констант, которые я ожидал определить, на самом деле являются константами. Вы получите ошибки ссылки, если заголовки достижимы, но фреймворк - нет.

1 голос
/ 11 февраля 2012

Так ведь. Я придумал 3 файла.

Constants.h

#define def_key(name) extern NSString *const name
#define def_int(name, value) extern int const name
#define def_type(type, name, value) extern type const name

#include "ConstantsDefs.h"

Constants.m

#import "Constants.h"

#undef def_key 
#define def_key(name) NSString *const name = @#name

#undef def_int
#define def_int(name, value) int const name = value

#undef def_type
#define def_type(type, name, value) type const name = value

#include "ConstantsDefs.h"

ConstantsDefs.h

def_key(kStringConstant);
def_int(kIntConstant, 313373);
def_type(float, kFloatConstant, 313373.0f);
1 голос
/ 21 ноября 2011

Основываясь на превосходных ответах @Barry Wark и @Matt Gallagher, и в моем первоначальном ответе (см. Конец этого ответа) есть третий подход, а именно использование комбинации макрос / включение, которая гарантирует, что вы вводите только имя переменной один раз, и поэтому он включается в файлы .h и .m одновременно.

"всегда есть другой путь ..."

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

в файле .h

#define defineKeysIn_h_File(key)   extern NSString * const key; 
#define defineKeysIn_m_File(key)   NSString * const key = @#key; 


#define myKeyDefineKeys(defineKey) \
/**start of key list*/\
defineKey(myKeyABC);\
defineKey(myKeyXYZ);\
defineKey(myKey123);\
/*end of key list*/

myKeyDefineKeys(defineKeysIn_h_File);

в файле .m

myKeyDefineKeys(defineKeysIn_m_File);

примечание к реализации

Вы можете использовать это более одного раза в нескольких заголовках, однако вам нужно изменить Чтобы имя myKeyDefineKeys было уникальным, я предлагаю присвоить ему тот же префикс, что и ключи, которые вы определяете, - в качестве примера я использовал «myKey» на протяжении всей статьи.

В другом файле я мог бы использовать «myOtherKeyDefineKeys».

Также не связывайтесь с макросами defineKeysIn_h_File и defineKeysIn_m_File, иначе вы получите предупреждение об изменении определения.

ОРИГИНАЛЬНЫЙ ОТВЕТ, ВСЕ ЕЩЕ ДЕЙСТВИТЕЛЬНО, НО БЕЗ УТОЧНЕНИЙ

Сначала создайте файл vanilla.h, удалите файл #ifdef и т. Д. И введите ключи, как показано ниже: (Это фрагмент из категории, которую я написал для расширения AVAudioPlayer)

//  playFromConsts.h


define_key(AVAudioPlayer_key_player);
define_key(AVAudioPlayer_key_duration);
define_key(AVAudioPlayer_key_filename);
define_key(AVAudioPlayer_key_filepath);
define_key(AVAudioPlayer_key_fileurl);
define_key(AVAudioPlayer_key_urlString);
define_key(AVAudioPlayer_key_envelope);
define_key(AVAudioPlayer_key_startDate);
define_key(AVAudioPlayer_key_linkToPlayer);
define_key(AVAudioPlayer_key_linkFromPlayer);
define_key(AVAudioPlayer_key_linkToPlayerEnvelope);
define_key(AVAudioPlayer_key_linkFromPlayerEnvelope);
define_key(AVAudioPlayer_key_deviceStartTime);
define_key(AVAudioPlayer_key_currentVolume);
define_key(AVAudioPlayer_key_fadeFromVolume);
define_key(AVAudioPlayer_key_fadeToVolume);
define_key(AVAudioPlayer_key_fadeTime);
define_key(AVAudioPlayer_key_segueTime);

Затем в вашем файле normal.h (где объявлен ваш @interface, @protocol и т. Д.) Поместите эти 3 строки (естественно, заменяя ваш заголовочный файл)

#define define_key(x) extern NSString * const x; 
#include "playFromConsts.h"
#undef define_key

наконец, в вашем файле .m, который связан с вашим файлом "@interface .h", поместите эти 3 строки:

#define define_key(x) NSString * const x = @#x; 
#include "playFromConsts.h"
#undef define_key

обратите внимание на "#include", а не на "#import" - мы действительно хотим включить этот файл более одного раза.

это сделает всю грязную работу и обеспечит ключами NSString * const.

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

0 голосов
/ 03 декабря 2008

Это зависит от дизайна вашего программного обеспечения. Предположим, у вас есть программное обеспечение для управления заданиями, и одно из ваших «значений по умолчанию» - это список каталогов, в которых можно сохранять различные элементы.

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

Или у вас может быть элемент Storagefile глобальной переменной с именем User Preferences. Все еще может быть одиночкой, но в данном случае это не имеет значения.

Для меня сложные значения по умолчанию (десятки различных типов классов) должны находиться в их собственном «пространстве», доступном для модели.

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

Опять же, это зависит от вашего дизайна.

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