2011-08-19 2 views
104

Большинство моделей в приложении iOS запрашивают веб-сервер. Я хотел бы иметь файл конфигурации, хранящий базовый URL-адрес сервера. Это будет выглядеть примерно так:Где хранить глобальные константы в приложении iOS?

// production 
// static NSString* const baseUrl = "http://website.com/" 

// testing 
static NSString* const baseUrl = "http://192.168.0.123/" 

комментируя одну линию или другой, я могу мгновенно изменить, какой сервер мои модели указывают. Мой вопрос: какова наилучшая практика хранения глобальных констант в iOS? В Android-программировании у нас есть этот встроенный strings resource file. В любом Activity (эквивалент UIViewController), мы можем получить эти строковые константы с:

String string = this.getString(R.string.someConstant); 

мне было интересно, если IOS SDK имеет аналогичное место для хранения констант. Если нет, то в чем заключается наилучшая практика в Objective-C?

ответ

142

Вы также могли бы сделать

#define kBaseURL @"http://192.168.0.123/" 

в файле заголовка "констант", скажем constants.h. Затем выполните

#include "constants.h" 

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

Таким образом, вы можете переключаться между серверами в зависимости от флагов компилятора, как:

#ifdef DEBUG 
    #define kBaseURL @"http://192.168.0.123/" 
#else 
    #define kBaseURL @"http://myproductionserver.com/" 
#endif 
+0

Я использую '' constants.h'' подход, объявляя 'static' переменные на основе' #ifdef VIEW_CONSTANTS ... # endif'.Таким образом, у меня есть один файл констант, основанный на приложении, но каждый из моих других файлов кода '# define' содержит разные наборы констант для включения до' # include'-файла констант (останавливает все эти «определенные, но не используемые» предупреждения компилятора). – darvids0n

+2

Есть два вопроса, с которыми я столкнулся с этим решением. Во-первых, когда я использовал '# decalare', я получил ошибку компиляции, указав« недопустимая директива preprocessing declare * ». Поэтому я заменил его на '# define'. Другая проблема заключается в использовании константы. Я хотел создать другую константу со статическим NSString * const fullUrl = [NSString stringWithFormat: @ "% @% @", kbaseUrl, @ "script.php"] ', но, видимо, было запрещено создавать константы с выражением. Я получаю ошибку "* элемент инициализации не является константой *". – JoJo

+0

Действительно, это '# define', а не' # declare'. Моя ошибка, я исправляю свой ответ. Однако странно, что вы получаете эту ошибку. Это связано с 'static NSString * const fullURL' частью, а не с константой (это макрос препроцессора, так что это как если бы вы написали' ... @ "% @% @", @ "something" , @ "script.php" '). BTW вместо использования 'stringWithFormat' вы могли бы просто написать' [kBaseUrl stringByAppendingString: @ "script.php"] ', что занимает меньше времени (нет необходимости разбирать строку формата). – Cyrille

1

подход я использовал до того, чтобы создать файл Settings.plist и загрузить его в NSUserDefaults при запуске с помощью registerDefaults:. Вы можете получить доступ к его содержимому следующему:

// Assuming you've defined some constant kMySettingKey. 
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey]; 

В то время как я не делал никакого Android развития, это звучит так, как будто это аналогично файл строка ресурсов вы описали. Единственным недостатком является то, что вы не можете использовать препроцессор для обмена между настройками (например, в режиме DEBUG). Я полагаю, вы могли бы загрузить в другом файле.

NSUserDefaults documentation.

+7

Разве это не слишком много, если все, что вы хотите, является константой? И также, зачем ставить его в потенциально модифицируемый файл? (Особенно, если это так важно, как IP-адрес вашего основного сервера, без которого ваше приложение не работает). – Cyrille

+0

Я чувствую, что этот подход имеет несколько преимуществ, причем наиболее важным является то, что ваши настройки возвращаются в правильном формате ('NSString',' NSNumber' и т. Д.). Конечно, вы можете обернуть свой '# define', чтобы сделать то же самое, но тогда их не так легко редактировать. Интерфейс редактирования plist тоже хорош. :) Хотя я согласен с тем, что вы не должны ставить супер секретные вещи, такие как ключи шифрования, я не слишком беспокоюсь о пользователях, которые ковыряются в местах, где их не должно быть - если они нарушают приложение, это их собственная ошибка , –

+1

Конечно, я согласен с вашими аргументами. Как вы говорите, я обертываю свой '# define' для возврата правильного типа, но я привык к редактированию таких файлов констант, поскольку я всегда научился помещать глобальные константы, подобные этому, в отдельный файл констант, обратно из дней я узнал Паскаля по старому 286 :) А что касается пользователя, который топает повсюду, я тоже согласен, это их вина. На самом деле это просто вопрос вкуса. – Cyrille

164

Ну, вы хотите, чтобы объявление локального интерфейсам оно относится к - файл приложения шириной константы не очень хорошая вещь.

Как хорошо, это предпочтительнее, чтобы просто объявить extern NSString* const символ, а не использовать #define:


SomeFile.h

extern NSString* const MONAppsBaseUrl; 

SomeFile.m

#import "SomeFile.h" 

#ifdef DEBUG 
NSString* const MONAppsBaseUrl = @"http://192.168.0.123/"; 
#else 
NSString* const MONAppsBaseUrl = @"http://website.com/"; 
#endif 

Помимо пропусков декларации Extern, совместимой с C++, это то, что вы, как правило, увидите в инфраструктурах Obj-C от Apple.

Если константа должна быть видна только одному файлу или функции, то static NSString* const baseUrl в вашем *.m хороша.

+25

Не уверен, почему принятый ответ содержит 40 голосов за поддержку #define - const действительно лучше. – occulus

+1

Определенно const NSString лучше, чем #define, это должен быть принятый ответ. #define создает новую строку каждый раз, когда используется определенное значение. – jbat100

+1

@ jbat100 Я не думаю, что он создает новую строку. Я думаю, что компилятор обнаруживает, создает ли ваш код одну и ту же статическую строку 300 000 раз и будет создавать ее только один раз. '@" foo "' не совпадает с '[[NSString alloc] initWithCString:" foo "]'. –

39

Как я определить глобальные константы:


AppConstants.h

extern NSString* const kAppBaseURL; 

AppConstants.m

#import "AppConstants.h" 

#ifdef DEBUG 
NSString* const kAppBaseURL = @"http://192.168.0.123/"; 
#else 
NSString* const kAppBaseURL = @"http://website.com/"; 
#endif 

Затем в {$} APP -prefix .pch файл:

#ifdef __OBJC__ 
    #import <UIKit/UIKit.h> 
    #import <Foundation/Foundation.h> 
    #import "AppConstants.h" 
#endif 

Если у вас возникли проблемы, сначала убедитесь, что у параметра Precompile Prefix Header установлено значение NO.

5

Вы также можете сцепить строковые константы, как это:

#define kBaseURL @"http://myServer.com" 
    #define kFullURL kBaseURL @"/api/request" 
0

Для ряда вы можете использовать его как

#define MAX_HEIGHT 12.5 
1

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

Я использую глобальные экземпляры классов (по 1 или 2 на каждый проект, если необходимо), для перегруппировки доступа к основным данным или некоторых торговля логикой.

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

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

несколько строк кода:

@interface RestaurantManager : NSObject 
    +(id) sharedInstance; 
    -(void)registerForTable:(NSNumber *)tableId; 
@end 

и реализация объекта:

@implementation RestaurantManager 

+ (id) sharedInstance { 
    static dispatch_once_t onceQueue; 

    dispatch_once(&onceQueue, ^{ 
     sharedInstance = [[self alloc] init]; 
     NSLog(@"*** Shared instance initialisation ***"); 
    }); 
    return sharedInstance; 
} 

-(void)registerForTable:(NSNumber *)tableId { 
} 
@end 

для его использования очень просто:

[[RestaurantManager sharedInstance] registerForTable: [NSNumber numberWithInt: 10]]

+3

Техническое название этого шаблона проектирования - Singleton. http://en.wikipedia.org/wiki/Singleton_pattern –

+0

Сохранение статических данных (не статических классов) в sharedmanager - это не очень хорошая идея. –

0

Я бы использовать объект конфигурации, который инициализирует из plist. Зачем беспокоиться о других классах с неуместными внешними вещами?

Я создал eppz!settigns soley по этой причине. См. Статью Advanced yet simple way to save to NSUserDefaults для включения значений по умолчанию из plist.

enter image description here

+0

Ссылка не работает –

+0

Правда. Wordpress как-то не решает ...:/... иди по этой прямой ссылке в любом случае http://blog.eppz.eu/?p=926: D – Geri

3
  1. определяет глобальную константу в YOURPROJECT-префиксе.файл pch.
  2. #define BASEURl @"http://myWebService.appspot.com/xyz/xx"
  3. затем в любом месте в проекте использовать BaseUrl:

    NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"https://stackoverflow.com/users/login"]; 
    

Обновлено: В Xcode 6 вы не найдете по умолчанию .PCH файл, созданный в вашем проекте. Поэтому, пожалуйста, используйте PCH File in Xcode 6, чтобы вставить файл .pch в свой проект.

Обновления: Для SWIFT

  1. Создать новый Swift файл [пусто без класса] говорят [AppGlobalMemebers]
  2. & Сразу объявляю/определить элемент

    Пример:

    var STATUS_BAR_GREEN : UIColor = UIColor(red: 106/255.0, green: 161/255.0, blue: 7/255.0, alpha: 1) // 
    
    1. Если вы хотите, чтобы определить приложение глобальный элемент в любом файле класса говорят AppDelegate или Singleton класс или любой, объявить данный элемент выше определение класса
3

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

#ifndef Constants_h 
#define Constants_h 

//Some constants 
static int const ZERO = 0; 
static int const ONE = 1; 
static int const TWO = 2; 

#endif /* Constants_h */ 

После того, что вы включили этот файл заголовка в заголовочном файле, который вы хотите. Вы включаете его в заголовочный файл для определенного класса, в который вы хотите включить его:

#include "Constants.h" 
0

Принятый ответ содержит 2 недостатки. Во-первых, поскольку другие указывают на использование #define, который сложнее отлаживать, вместо этого используйте extern NSString* const kBaseUrl. Во-вторых, он определяет один файл для констант. IMO, это неправильно, потому что большинство классов не нуждаются в доступе к этим константам или для доступа ко всем из них, плюс файл может раздуваться, если все константы объявлены там. Лучшее решение было бы модуляризует константы в 3 различных слоях:

  1. Система слой: SystemConstants.h или AppConstants.h, который описывает константы в глобальном масштабе, которые могут быть доступны с помощью любого класса в системе. Объявите здесь только те константы, к которым необходимо получить доступ из разных классов, которые не связаны.

  2. Уровень модуля/подсистемы: ModuleNameConstants.h, описывает набор констант, типичных для набора связанных классов, внутри модуля/подсистемы.

  3. Слой класса: константы находятся в классе и используются только им.

Только 1,2 связаны с вопросом.

Смежные вопросы