Определяем устройство iOS в Swift: UI_USER_INTERFACE_IDIOM() — FAQ

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Когда код работает на симуляторе, но ломается на реальном устройстве: разбираемся с UI_USER_INTERFACE_IDIOM() в Swift

Вы когда-нибудь писали приложение, которое идеально выглядит на симуляторе iPhone 14 Pro, а на iPad Mini превращается в кашу? Или наоборот — ваш модный iPad-интерфейс съезжает на старом iPod touch? Знакомая боль, правда?

Разработчики iOS часто сталкиваются с необходимостью узнать, на каком устройстве запущено приложение. Казалось бы, что может быть проще? Но дьявол, как всегда, кроется в деталях. Легендарный вопрос на Stack Overflow про UI_USER_INTERFACE_IDIOM() собрал тысячи просмотров, а это значит, что даже опытные программисты иногда путаются в нюансах.

В этой статье мы разложим по полочкам всё, что нужно знать об определении устройства в Swift. Никакой воды — только практика, живые примеры и ответы на самые частые вопросы.

Что такое UI_USER_INTERFACE_IDIOM() и почему о нём говорят?

Это старая добрая функция из эпохи Objective-C. Она возвращает значение типа UIUserInterfaceIdiom, которое указывает, с каким типом устройства мы имеем дело: iPhone, iPad, TV или CarPlay.

Вот как это выглядело в классическом Objective-C:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    // Это iPad
} else {
    // Это iPhone или iPod touch
}

Но Swift — язык более строгий и безопасный. Прямое использование этой C-функции не всегда удобно. На смену пришёл более современный подход через UIDevice.current.

Как правильно определить устройство в Swift: два рабочих способа

Способ №1 — классика через UIDevice (рекомендуется):

import UIKit

let deviceIdiom = UIDevice.current.userInterfaceIdiom

switch deviceIdiom {
case .phone:
    print("Это iPhone или iPod touch")
case .pad:
    print("Это iPad")
case .tv:
    print("Это Apple TV")
case .carPlay:
    print("Это CarPlay")
case .mac:
    print("Это Mac Catalyst или Mac")
@unknown default:
    print("Неизвестное устройство (возможно, будущее)")
}

Важно: Кейс .mac появился в iOS 14+. Если ваше приложение поддерживает более старые версии, используйте @unknown default для обработки будущих типов.

Способ №2 — совместимость с Objective-C кодом (если нужно):

if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone {
    print("Работаем на телефоне")
}

Оба варианта корректны, но первый — более идиоматичный для Swift.

Частые вопросы и подводные камни

1. Почему на iPad mini определяется iPhone?

Это самый популярный вопрос. Вы запускаете приложение на iPad mini, а userInterfaceIdiom упорно возвращает .phone. В чём дело?

Ответ простой и неочевидный: режим масштабирования (Scale Mode). Если в настройках вашего приложения (Target → General → Deployment Info) выбран режим "iPhone", то даже на физическом iPad система будет эмулировать iPhone.

Решение: проверьте настройки проекта.

  • Зайдите в Target вашего приложения
  • General → Deployment Info
  • Devices: выберите "Universal" (если приложение должно работать на всех устройствах)

Если вы выбрали "iPhone Only", то на iPad приложение будет работать в режиме совместимости (как на большом iPhone), и idiom будет .phone.

2. Как отличить iPhone от iPod touch?

UI_USER_INTERFACE_IDIOM() не различает iPhone и iPod touch — оба возвращают .phone. Для точного определения модели нужно использовать UIDevice.current.model или modelName через sysctl.

Пример расширения для получения точного имени модели:

import UIKit

extension UIDevice {
    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.compactMap { $0.value as? Int8 }
            .filter { $0 != 0 }
            .map { String(UnicodeScalar(UInt8($0))) }
            .joined()
        return identifier
    }
}

// Использование:
print(UIDevice.current.modelName) // Например: "iPhone14,2" или "iPod9,1"

Затем вы можете сопоставить идентификатор с известными моделями через словарь или парсить строку.

3. А что с iPadOS 13+ и поддержкой мыши/трекпада?

С появлением поддержки мыши и трекпада на iPad, многие разработчики пытаются использовать userInterfaceIdiom для определения, подключено ли указывающее устройство. Так делать нельзя! Idiom отвечает только за тип устройства, а не за подключённые аксессуары.

Для проверки подключения мыши или трекпада используйте:

if UIDevice.current.userInterfaceIdiom == .pad {
    // Проверяем, есть ли у нас указательное устройство
    if UIPointerInteraction.isSupported {
        print("Трекпад или мышь подключены (или эмулируются)")
    }
}

Но лучше проверять через GCController.controllers() или слушать уведомления GCMouseDidConnect.

4. Почему на симуляторе всё работает, а на реальном устройстве — нет?

Симулятор — штука хитрая. Он может эмулировать разные устройства, но не всегда точно передаёт их поведение. Например, на симуляторе iPad с iPhone-режимом масштабирования userInterfaceIdiom вернёт .phone, и вы можете не заметить подвоха.

Совет: Всегда тестируйте определение устройства на реальных девайсах. Хотя бы на одном iPad и одном iPhone.

Продвинутые техники: когда простого idiom недостаточно

Адаптивный интерфейс через size classes

В современном iOS-разработке редко нужно жёстко привязываться к типу устройства. Гораздо гибче использовать Size Classes (горизонтальный и вертикальный классы размера).

Пример в коде:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    if traitCollection.horizontalSizeClass == .regular {
        // Широкий экран (iPad в альбомной, iPhone Plus в альбомной)
        showSidebar()
    } else {
        // Узкий экран (iPhone в портрете)
        hideSidebar()
    }
}

Этот подход позволяет адаптировать интерфейс под любые устройства, включая будущие модели с нестандартными размерами.

Проверка на наличие Face ID или Touch ID

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

import                

Блоги

Рекомендаций по книгам