Как #определить NSString для глобального использования?

#objective-c #ios4

#objective-c #ios4

Вопрос:

Я новичок в Objective-C. По сути, я хочу сохранить набор URL-адресов конечных точек в виде строк для использования в моем приложении, но мне нужен другой домен в зависимости от того, находится приложение в режиме отладки или нет. Я подумал, что было бы полезно использовать файл заголовка ( Common.h например) с некоторыми простыми определениями, такими как:

 #ifdef DEBUG
    #define kAPIEndpointHost @"http://example.dev"
#else
    #define kAPIEndpointHost @"http://www.example.com"
#endif

#define kAPIEndpointLatest          [kAPIEndpointHost stringByAppendingString:@"/api/latest_content"]
#define kAPIEndpointMostPopular     [kAPIEndpointHost stringByAppendingString:@"/api/most_popular"]
  

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

Каков «правильный» способ сделать это? Было бы разумнее просто иметь правильный класс с методами класса, которые возвращают правильные значения конечной точки?

РЕДАКТИРОВАТЬ: Просто для ясности, у меня больше всего проблем с «Последними» и «наиболее популярными» строками, которые основаны на строке host. Компилятору не нравится stringByAppendingString часть #defines.

Комментарии:

1. Я не вижу, что в этом плохого, tbph.

2. Компилятор жалуется на stringByAppendingString часть. Я думаю, вы не можете # определить константу на основе другой константы, подобной этой.

3. Каково фактическое сообщение об ошибке компилятора? Я только что использовал ваш фрагмент кода выше, и он скомпилировался / запустился просто отлично.

4. Ваш код не основывает константу на константе, он определяет макрос времени компиляции, который заменяет все вхождения kAPIEndpointLatest на [kAPIEndpointHost stringByAppendingString:@»/api/latest_content»]. При этом kAPIEndpointHost также заменяется в зависимости от того, определена DEBUG или нет.

Ответ №1:

Если вы просто объединяете строки, вы можете использовать объединение строк во время компиляции:

 #ifdef DEBUG
    #define kAPIEndpointHost @"http://example.dev"
#else
    #define kAPIEndpointHost @"http://www.example.com"
#endif

#define kAPIEndpointLatest          (kAPIEndpointHost @"/api/latest_content")
#define kAPIEndpointMostPopular     (kAPIEndpointHost @"/api/most_popular")
  

Комментарии:

1. Я думаю, это было действительно то, о чем я спрашивал. Спасибо!

2. Что теперь, если я хочу использовать переменную вместо жестко запрограммированного URL? Например. #определить имя переменной kAPIEndpointHost, где имя переменной инициализировано в предыдущем представлении.

3. @JayprakashDubey Прежде всего, я бы избегал использования внешних переменных в макросах. Вам пришлось бы использовать метод NSString, поскольку подобная конкатенация работает только во время компиляции. Я бы #define kAPILatestPath @"/api/latest_content" собрал это воедино в функции, используя NSString* APIEndpointLatest = [variableName stringByAppendingString:APILatestPath];

4. @ArtemZaytsev Это плохо документированная языковая функция; она наследуется от C, где "a" "b" определено так же, как "ab" .

Ответ №2:

Мне не нравится использовать #defines для строковых констант. Если вам нужны глобальные константы и конкатенация во время компиляции. Я бы использовал следующее:

Заголовочный файл:

 extern NSString *const kAPIEndpointHost;
extern NSString *const kAPIEndpointLatestPath;
extern NSString *const kAPIEndpointMostPopularPath;
  

Файл реализации:

 #ifdef DEBUG
#define API_ENDPOINT_HOST @"http://example.dev"
#else
#define API_ENDPOINT_HOST @"http://www.example.com"
#endif

NSString *const kAPIEndpointHost = API_ENDPOINT_HOST;
NSString *const kAPIEndpointLatestPath = (API_ENDPOINT_HOST @"/api/latest_content");
NSString *const kAPIEndpointMostPopularPath = (API_ENDPOINT_HOST @"/api/most_popular");
  

Комментарии:

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

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

3. @Eric Основная проблема с использованием постоянных строк вместо макросов заключается в том, что вы можете в конечном итоге сохранить постоянную строку, когда вашему приложению это не нужно. Преимущество использования #define заключается в том, что, создавая новые строки при каждом использовании, вы также даете операционной системе возможность освободить память, используемую для хранения строки.

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

Ответ №3:

В вашем заголовочном файле:

 extern NSString *const kAPIEndpointHost;
extern NSString *const kAPIEndpointLatestPath;
extern NSString *const kAPIEndpointMostPopularPath;
  

В вашем файле реализации:

 #ifdef DEBUG
    NSString *const kAPIEndpointHost = @"http://example.dev";
#else
    NSString *const kAPIEndpointHost = @"http://www.example.com";
#endif

NSString *const kAPIEndpointLatestPath = @"/api/latest_content";
NSString *const kAPIEndpointMostPopularPath = @"/api/most_popular";
  

Комментарии:

1. Спасибо за ответ. Однако я все еще не уверен в том, как определить последние и наиболее популярные константы на основе значения host.

2. @mirthlab, я бы просто объединил их в коде при создании NSURL объекта.

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

4. В чем преимущество этого метода перед строками, определенными препроцессором в одном заголовочном файле? Это просто хорошая практика, чтобы ваши определения строк находились в отдельном файле? Есть ли преимущество в производительности?