Как определить #define на основе версии iOS?

У меня есть Constants.h файл в моем приложении, где я #define размещаю вещи для всего приложения для быстрого доступа позже. Однако мне трудно, #defineing на основе версии iOS. Вот что я пробовал:

#ifdef __IPHONE_7_0

#define kHamburgerImage [UIImage imageNamed:@"reveal_menu_icon_portrait_ios7.png"];

#else

#define kHamburgerImage [UIImage imageNamed:@"reveal_menu_icon_portrait.png"];

#endif

То, что там написано iOS 7, не означает, что это под соглашением о неразглашении, о, доводчики!

Что отлично работает - для iOS 7. Однако, когда я запускаю свое приложение на iOS 6, #define по-прежнему остается iOS 7 - кажется, что #ifdef никогда не принимается во внимание.

Что я могу сделать, чтобы исправить это?


person Undo    schedule 24.07.2013    source источник
comment
Вы не можете этого сделать. Версия iOS должна быть решением во время выполнения, а не во время компиляции.   -  person rmaddy    schedule 25.07.2013
comment
@rmaddy Прости! Я думаю, это не работает - это работает для обычного кода, но не для #define...   -  person Undo    schedule 25.07.2013
comment
Правильно, если вы не делаете это, чтобы иметь возможность создавать код с двумя разными версиями Xcode, вам нужно использовать проверки времени выполнения, а не проверки времени компиляции. И #if, и #define являются функциями времени компиляции.   -  person rmaddy    schedule 25.07.2013


Ответы (3)


Вместо проверки во время компиляции вам нужны проверки во время выполнения. Это означает, что вы не можете использовать #define. Я предлагаю использовать статическую переменную, которая инициализируется во время выполнения в зависимости от версии iOS. Ниже приведен пример, если вам нужно значение только в одном файле.

Некоторый .m файл:

static UIImage *kHamburgerImage = nil;

+ (void)initialize {
    // This assumes you only support iOS 6 and later - adjust as needed
    if ([[UIDevice currentDevice].systemVersion hasPrefix:@"6"]) {
        kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait.png"];
    } else {
        kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait_ios7.png"];
    }
}

Изменить: поскольку они должны быть глобальными, вы должны сделать это:

Константы.ч:

extern UIImage *kHamburgerImage;

@interface Constants
@end

Константы.м:

UIImage *kHamburgerImage = nil;

@implementation Constants

+ (void)initialize {
    // This assumes you only support iOS 6 and later - adjust as needed
    if ([[UIDevice currentDevice].systemVersion hasPrefix:@"6"]) {
        kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait.png"];
    } else {
        kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait_ios7.png"];
    }
}

@end

Но это страдает от проблемы. Если вы не предпримете определенных шагов, доступ к этим глобальным переменным может привести к nil указателям. Они инициализируются только в том случае, если на класс действительно ссылаются. Я предлагаю, чтобы в качестве первой строки вашего application:didFinishLaunchingWithOptions: вы сделали:

[Constants class];

Это гарантирует вызов инициализатора и настройку констант до того, как вы будете использовать их где-либо еще в своем коде.

person rmaddy    schedule 24.07.2013
comment
Итак... Изменить мой файл Constants.h на файл .m? - person Undo; 25.07.2013
comment
Если они используются в глобальном файле, вам понадобятся Constants.h и Constants.m. В .h объявите их как extern UIImage *kHamburgerImage;. Затем в .m удалите ключевое слово static. - person rmaddy; 25.07.2013
comment
И я все еще мог бы просто импортировать файл Constants.h и сослаться на него как kHamburgerImage? - person Undo; 25.07.2013
comment
Хммм... Я поместил #define kHamburgerImage extern UIImage *kHamburgerImage; в свой файл .h и скопировал ваш код, удалив static, в новый файл .m, и получаю Expected expression ошибки везде, где я на него ссылаюсь. - person Undo; 25.07.2013
comment
Есть ли что-нибудь еще, что должно быть в файле .m? @implementation? - person Undo; 25.07.2013
comment
Эх, отказаться от этого. Не стоит - я просто буду проверять версию ОС каждый раз, когда ссылаюсь на нее, и на ее основе беру другой #define. Спасибо, в любом случае! - person Undo; 25.07.2013
comment
Теперь это сработает. Детали теряются при вводе всего этого в SO без использования хорошей IDE. - person rmaddy; 25.07.2013
comment
Хорошо, я попробую еще раз. Переходите на исходный контроль! - person Undo; 25.07.2013
comment
Теперь я получаю Undefined symbols for architecture armv7s: "_kHamburgerImage", referenced from: ошибки компоновщика для каждого файла, из которого я на него ссылаюсь. - person Undo; 25.07.2013
comment
Одинаково ли пишутся переменные как в Constants.h, так и в Constants.m? Вы удалили static из переменной в Constants.m? И правильно ли нацелены Constants.m? - person rmaddy; 25.07.2013
comment
@Val Нет, этот ответ не является неправильным. Пожалуйста, объясните, почему вы так думаете. - person rmaddy; 29.10.2014
comment
@rmaddy Я согласен, ты прав. Ответ Нанды работает только на разных SDK симуляторов. Я удалил свой предыдущий комментарий. - person Val; 30.10.2014

По крайней мере, вы можете сократить свой код, определив проверку iOS как макрос.

#define IS_IOS7 [[UIDevice currentDevice].systemVersion hasPrefix:@"7"]

И тогда ваш новый код станет более читабельным,

if (IS_IOS7) {
    kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait_ios7.png"];
} else {
    kHamburgerImage = [UIImage imageNamed:@"reveal_menu_icon_portrait.png"];
}
person John Beck    schedule 30.09.2013
comment
Это работает! Он просто заменяет IS_IOS7 следующим кодом во время компиляции. Он производит то, что было бы нечитаемым кодом. - person John Beck; 10.10.2013

Вы должны использовать #ifndef вместо #ifdef. Вот код. Я надеюсь, что это поможет вам.

#ifndef __IPHONE_7_0

#define kHamburgerImage [UIImage imageNamed:@"reveal_menu_icon_portrait_ios7.png"];

#else

#define kHamburgerImage [UIImage imageNamed:@"reveal_menu_icon_portrait.png"];

#endif
person Nanda    schedule 27.12.2013
comment
@Val Нет, этот ответ не может работать должным образом. Когда приложение скомпилировано, будет определен только один kHamburgerImage. Таким образом, во время выполнения, независимо от версии iOS, это единственное значение будет использоваться всеми версиями. - person rmaddy; 29.10.2014
comment
@rmaddy Я согласен, ты прав. Это работает только на разных SDK симуляторов. - person Val; 30.10.2014