Avatar ·

Определение типа устройства (iPhone/iPad) в Swift: UI_USER_INTERFACE_IDIOM() и альтернативы

Всем привет! Я только начал изучать Swift и столкнулся с проблемой при определении типа устройства (iPhone или iPad). В старых проектах на Objective-C я видел макрос UI_USER_INTERFACE_IDIOM(), но в Swift он не работает напрямую.

Мне нужно написать код, который будет по-разному вести себя на iPad и iPhone. Например, на iPad я хочу показывать контроллер как UISplitViewController, а на iPhone — как обычный UINavigationController.

Вот что я пробовал, но это не компилируется:

if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad {
    // iPad
} else {
    // iPhone
}

Xcode выдаёт ошибку: "Use of unresolved identifier 'UI_USER_INTERFACE_IDIOM'". Как правильно определить тип устройства в Swift? Есть ли более современный способ, чем этот старый макрос? Заранее спасибо!

<<>>

Правильный способ определения типа устройства в Swift

В Swift макрос UI_USER_INTERFACE_IDIOM() из Objective-C недоступен, но есть несколько эквивалентных и более современных решений. Вот основной подход через свойство UIDevice.current.userInterfaceIdiom.

Базовое использование

import UIKit

if UIDevice.current.userInterfaceIdiom == .pad {
    print("Это iPad")
} else if UIDevice.current.userInterfaceIdiom == .phone {
    print("Это iPhone")
} else {
    print("Другое устройство (например, iPod touch или Apple TV)")
}

Пример с UISplitViewController

Вот как можно реализовать адаптивное поведение, которое вы описали:

func configureInitialViewController() {
    let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
    
    if UIDevice.current.userInterfaceIdiom == .pad {
        // На iPad используем SplitViewController
        let splitVC = mainStoryboard.instantiateViewController(withIdentifier: "SplitViewController")
        window?.rootViewController = splitVC
    } else {
        // На iPhone используем NavigationController
        let navVC = mainStoryboard.instantiateViewController(withIdentifier: "NavigationController")
        window?.rootViewController = navVC
    }
}

Дополнительные возможности

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

// Проверка на iPad в альбомной ориентации
if UIDevice.current.userInterfaceIdiom == .pad &&
   UIDevice.current.orientation.isLandscape {
    print("iPad в альбомной ориентации")
}

// Использование trait collections (рекомендуется для адаптивного дизайна)
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    
    if traitCollection.horizontalSizeClass == .regular &&
       traitCollection.verticalSizeClass == .regular {
        print("Большой экран (обычно iPad)")
    }
}

Почему не работает UI_USER_INTERFACE_IDIOM()?

  • Это макрос из Objective-C, который не импортируется в Swift автоматически.
  • В Swift используется более безопасный и типизированный подход через UIDevice.
  • Макрос возвращает UIUserInterfaceIdiom (enum), который в Swift доступен как UIUserInterfaceIdiom с значениями .phone, .pad, .tv, .carPlay и .unspecified.

Советы для начинающих

  1. Всегда используйте UIDevice.current.userInterfaceIdiom — это стандартный способ в Swift.
  2. Для адаптивного интерфейса предпочтительнее использовать traitCollection или size classes.
  3. Не забывайте импортировать UIKit, так как UIDevice является его частью.
<<>>

Альтернативный подход: использование traitCollection

Вместо прямой проверки типа устройства, Apple рекомендует использовать trait collections и size classes. Это более гибкий подход, который работает не только с iPhone/iPad, но и с разными размерами экранов (например, iPad в режиме Split View или iPhone SE).

// Проверка через traitCollection
if traitCollection.horizontalSizeClass == .regular &&
   traitCollection.verticalSizeClass == .regular {
    print("Устройство с большим экраном (iPad или iPhone Plus в альбоме)")
} else {
    print("Устройство с компактным экраном")
}

// Адаптивный layout с помощью UIUserInterfaceSizeClass
override func willTransition(to newCollection: UITraitCollection, 
                             with coordinator: UIViewControllerTransitionCoordinator) {
    super.willTransition(to: newCollection, with: coordinator)
    
    if newCollection.horizontalSizeClass == .compact {
        showCompactLayout()
    } else {
        showRegularLayout()
    }
}

Преимущества:

  • Код работает корректно на всех устройствах, включая iPad в режиме Split View.
  • Не привязывается к конкретному типу устройства, что делает приложение более универсальным.
  • Лучше подходит для адаптивных интерфейсов в SwiftUI и UIKit.

Используйте UIDevice.current.userInterfaceIdiom только когда вам действительно нужно знать тип устройства (например, для аналитики или выбора специфических жестов). Для layout всегда предпочтительнее traitCollection.