Лучший способ программно определять оборудование iPad/iPhone

Причина, по которой мне нужно выяснить, состоит в том, что на iPad UIPickerView имеет ту же высоту в альбомной ориентации, что и в портретной. На айфоне все иначе. Руководство по программированию для iPad вводит значение "идиома" в UIDevice:

    UIDevice* thisDevice = [UIDevice currentDevice];
    if(thisDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
    {
        // iPad
    }
    else
    {
        // iPhone
    }

который работает нормально, пока вы находитесь в iPad (3.2), но не в iPhone (3.1.3) - так что, похоже, также необходим ifdef для условной компиляции этой проверки, например:

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30200
        UIDevice* thisDevice = [UIDevice currentDevice];
        if(thisDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
        {
            // etc.
        }
#endif

Для меня это выглядит очень неуклюже. Какой способ лучше?

9 ответов

Решение

Я отвечаю на это сейчас (и в более поздние сроки), потому что многие из существующих ответов довольно стары, и большинство проголосовавших на самом деле, по-видимому, неверны в соответствии с текущими документами Apple (iOS 8.1, 2015)!

Чтобы доказать мою точку зрения, это комментарий из заголовочного файла Apple (всегда смотрите на источник Apple и заголовки):

/*The UI_USER_INTERFACE_IDIOM() macro is provided for use when
  deploying to a version of the iOS less than 3.2. If the earliest
  version of iPhone/iOS that you will be deploying for is 3.2 or
  greater, you may use -[UIDevice userInterfaceIdiom] directly.*/

Поэтому рекомендуемый в настоящее время APPLE способ обнаружения iPhone и iPad заключается в следующем:

1) В версиях iOS PRIOR до 3.2 используйте макрос Apple:

// for iPhone use UIUserInterfaceIdiomPhone
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

2) В версиях iOS 3.2 или новее используйте свойство в [UIDevice currentDevice]:

// for iPhone use UIUserInterfaceIdiomPhone
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)

Проверка во время выполнения (ваш первый способ) полностью отличается от #if во время компиляции. Директивы препроцессора не дадут вам универсальное приложение.

Предпочтительным способом является использование макроса Apple:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
     // The device is an iPad running iPhone 3.2 or later.
}
else
{
     // The device is an iPhone or iPod touch.
}

Используйте 3.2 в качестве базового SDK (поскольку макрос не определен до 3.2), вы можете использовать предыдущие версии ОС, чтобы запустить его на iPhone.

Мне нравится моя функция isPad(). Тот же код, но держите его вне поля зрения и только в одном месте.

Мое решение (работает на 3.2+):

#define IS_IPHONE (!IS_IPAD)
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone)

затем,

if (IS_IPAD)
    // do something

или же

if (IS_IPHONE)
    // do something else

В Swift используйте свойство экземпляра userInterfaceIdiom как

if UIDevice.current.userInterfaceIdiom == .phone {
     print("iPhone")
 }

& Для других устройств -

  switch UIDevice.current.userInterfaceIdiom {
    case .pad:
        print("iPad")
    case .phone:
        print("iPhone")
    case .tv:
        print("TV")
    case .carPlay:
        print("carPlay")
    default: break;
  }
extension UIDevice {

   var isIPad: Bool {
      return UIDevice.current.userInterfaceIdiom == .pad
   }
}

Если 1- у вас уже есть приложение, установленное на вашем устройстве, 2- вы изменяете настройки его сборки на "Универсальное" приложение, 3- устанавливаете приложение на свое устройство поверх уже существующего приложения (без удаления предыдущего)

Вы можете обнаружить, что предлагаемые здесь решения для обнаружения iPhone /iPad не работают. Сначала удалите приложение, которое было "только" для iPad /iPhone, и установите его заново на свое устройство.

Поместите этот метод в ваш делегат приложения, чтобы вы могли вызывать его где угодно, используя [[[UIApplication sharedApplication] делегат] isPad]

-(BOOL)isPad
{
    BOOL isPad;
    NSRange range = [[[UIDevice currentDevice] model] rangeOfString:@"iPad"];
    if(range.location==NSNotFound)
    {
        isPad=NO;


    }
    else {
        isPad=YES;
    }

    return isPad;
}

Если вы используете функции, которые не являются обратно совместимыми, я обнаружил, что лучший способ для меня - создать #define в предварительно скомпилированном заголовке. Пример:

#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_3_2
#define USING_4_X
#endif

Затем в своем коде вы можете сделать это:

BOOL exists = NO;
#ifdef USING_4_X        
exists = [SomeObject someMethod:[url lastPathComponent]];
#else
exists = [SomeObject someMethod:[[url path] lastPathComponent]];
#endif
BOOL isIpad()
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return YES;
    }
    return NO;
}
Другие вопросы по тегам