Как заставить UI_USER_INTERFACE_IDIOM() работать с iPhone OS SDK < 3.2
Apple рекомендует использовать следующий код для определения того, работает ли он на iPad или iPhone/iPod Touch:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iPhone 3.2 or later.
// [for example, load appropriate iPad nib file]
}
else {
// The device is an iPhone or iPod touch.
// [for example, load appropriate iPhone nib file]
}
Проблема в том, что UI_USER_INTERFACE_IDIOM() и UIUserInterfaceIdiomPad НЕ определены в SDK до 3.2. Это, кажется, полностью разрушает цель такой функции. Их можно скомпилировать и запустить только на iPhone OS 3.2 (iPhone OS 3.2 может работать только на iPad). Поэтому, если вы можете использовать UI_USER_INTERFACE_IDIOM(), результат всегда будет указывать на iPad.
Если вы включите этот код и целевую ОС 3.1.3 (самую последнюю ОС iPhone / iPod Touch) для тестирования кода универсального приложения для iPhone, вы получите ошибки компилятора, так как символы не определены в 3.1.3 или более ранней, при компиляции для симулятора iPhone 3.1.3.
Если это рекомендуемый Apple подход к обнаружению устройств во время выполнения, что я делаю не так? Кому-нибудь удалось использовать этот подход к обнаружению устройств?
8 ответов
Я делаю это, чтобы получить код для компиляции в 3.1.3 и 3.2:
BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
if (iPad) {
// iPad specific code here
} else {
// iPhone/iPod specific code here
}
Я также написал краткое сообщение об этом в блоге здесь: http://www.programbles.com/2010/04/03/compiling-conditional-code-in-universal-iphone-ipad-applications/
Это то, что я использую:
- (BOOL) amIAnIPad {
#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200)
if ([[UIDevice currentDevice] respondsToSelector: @selector(userInterfaceIdiom)])
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
#endif
return NO;
}
Это условно компилируется, так что вы все равно можете собрать для 3.0 сим. Затем он проверяет, отвечает ли класс UIDevice на селектор. Если что-то из этого не получится, это не iPad.
Если это рекомендуемый Apple подход к обнаружению устройств во время выполнения, что я делаю не так? Кому-нибудь удалось использовать этот подход к обнаружению устройств?
Это решение для обнаружения во время выполнения:
#define isIPhone (![[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] || [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
После этого вы можете легко проверить это в любом месте вашего кода:
if (isIPhone) { ... }
Разница между этим и использованием #if / #ifdef заключается в том, что это тестирование во время выполнения, а #if - тестирование во время компиляции.
Я думаю, что тестирование во время выполнения лучше, потому что в этом случае вы можете использовать один подходящий для любой версии ОС. Если вы используете проверку во время компиляции, вам нужно будет создавать разные исполняемые файлы для разных версий ОС.
Если ваша проблема связана с ошибками во время компиляции, вам следует просто выполнить компиляцию с последней версией SDK (см. Также Как получить доступ к слабосвязанной среде в iOS?).
Я считаю, что ответ просто не пытайтесь запустить код на iPhone Simulator 3.1.3 или более ранней версии. Всегда компилируйте с 3.2 SDK. Симулятор iPhone 3.2 доставит вам симулятор iPad или скомпилирует для iPhone Device 3.2 и поместит приложение на телефон, чтобы протестировать его.
Невозможно скомпилировать SDK 3.2 и использовать симулятор 3.1.3 или более ранней версии.
Вместо любого материала на основе компилятора я использую:
- (BOOL)deviceIsAnIPad {
if ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)])
//We can test if it's an iPad. Running iOS3.2+
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
return YES; //is an iPad
else
return NO; //is an iPhone
else
return NO; //does not respond to selector, therefore must be < iOS3.2, therefore is an iPhone
}
Объявите, используя это
#ifdef UI_USER_INTERFACE_IDIOM
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#else
#define IS_IPAD false
#endif
тогда используйте проверку как ниже
#define DetailLabel_PosX (IS_IPAD ? 200 : 160)
Есть также некоторые определения для проверки iphone 5
#define IS_IPHONE5 (([[UIScreen mainScreen] bounds].size.height-568)?NO:YES)
#define IOS_OLDER_THAN_6 ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0 )
UI_USER_INTERFACE_IDIOM() и UIUserInterfaceIdiomPad можно использовать на iOS3.2 и выше, важной частью является "вверх". Конечно. iOS3.2 предназначена только для iPad, но iOS4.0 и более поздние версии работают как на iPhone, так и на iPad, поэтому проверка не так бессмысленна, как вы думаете.
Это, кажется, полностью разрушает цель такой функции. Их можно скомпилировать и запустить только на iPhone OS 3.2 (iPhone OS 3.2 может работать только на iPad). Поэтому, если вы можете использовать UI_USER_INTERFACE_IDIOM(), результат всегда будет указывать на iPad.
Это совершенно неверно. Его можно скомпилировать в Base SDK версии 3.2, но можно запустить в любой ОС, если вы правильно установите цель развертывания.