在Swift中使用UI_USER_INTERFACE_IDIOM()检测当前设备

什么是等价的UI_USER_INTERFACE_IDIOM()在Swift检测之间的iPhone和iPad?

在Swift编译时,我得到一个Use of unresolved identifier错误。

188296 次浏览

在使用Swift时,你可以使用enum UIUserInterfaceIdiom,定义为:

enum UIUserInterfaceIdiom : Int {
case unspecified
    

case phone // iPhone and iPod touch style UI
case pad   // iPad style UI (also includes macOS Catalyst)
}

所以你可以这样使用它:

UIDevice.current.userInterfaceIdiom == .pad
UIDevice.current.userInterfaceIdiom == .phone
UIDevice.current.userInterfaceIdiom == .unspecified

或者使用Switch语句:

    switch UIDevice.current.userInterfaceIdiom {
case .phone:
// It's an iPhone
case .pad:
// It's an iPad (or macOS Catalyst)


@unknown default:
// Uh, oh! What could it be?
}

UI_USER_INTERFACE_IDIOM()是Objective-C宏,定义为:

#define UI_USER_INTERFACE_IDIOM() \ ([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] ? \ [[UIDevice currentDevice] userInterfaceIdiom] : \ UIUserInterfaceIdiomPhone)

另外,请注意,即使在使用Objective-C时,UI_USER_INTERFACE_IDIOM()宏也只在针对iOS 3.2及以下时才需要。当部署到iOS 3.2及更高版本时,可以直接使用[UIDevice userInterfaceIdiom]

if / else案例:

 if UIDevice.current.userInterfaceIdiom == .pad {
// iPad
} else {
// not iPad (iPhone, mac, tv, carPlay, unspecified)
}

你应该使用这个GBDeviceInfo框架或…

苹果公司这样定义:

public enum UIUserInterfaceIdiom : Int {


case unspecified


case phone // iPhone and iPod touch style UI


case pad // iPad style UI


@available(iOS 9.0, *)
case tv // Apple TV style UI


@available(iOS 9.0, *)
case carPlay // CarPlay style UI
}

所以对于严格定义的设备可以使用本代码

struct ScreenSize
{
static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}


struct DeviceType
{
static let IS_IPHONE_4_OR_LESS  = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0
static let IS_IPHONE_5          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0
static let IS_IPHONE_6_7          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0
static let IS_IPHONE_6P_7P         = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0
static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0
static let IS_IPAD_PRO          = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1366.0
}

如何使用

if DeviceType.IS_IPHONE_6P_7P {
print("IS_IPHONE_6P_7P")
}

检测iOS版本

struct Version{
static let SYS_VERSION_FLOAT = (UIDevice.current.systemVersion as NSString).floatValue
static let iOS7 = (Version.SYS_VERSION_FLOAT < 8.0 && Version.SYS_VERSION_FLOAT >= 7.0)
static let iOS8 = (Version.SYS_VERSION_FLOAT >= 8.0 && Version.SYS_VERSION_FLOAT < 9.0)
static let iOS9 = (Version.SYS_VERSION_FLOAT >= 9.0 && Version.SYS_VERSION_FLOAT < 10.0)
}

如何使用

if Version.iOS8 {
print("iOS8")
}

我是这样做的:

UIDevice.current.model

它显示了设备的名称。

检查是iPad还是iPhone:

if ( UIDevice.current.model.range(of: "iPad") != nil){
print("I AM IPAD")
} else {
print("I AM IPHONE")
}

供参考,我已经使用UI_USER_INTERFACE_IDIOM()为我的应用程序写在Swift。应用程序可以很好地使用XCode 6.3.1编译,没有任何警告,在模拟器(任何选择的设备)和我所有的真实设备(iPhone, iPad)上运行良好,iOS版本从7.1到8.3。

然而,这款应用在苹果评测者的设备上崩溃了(并被拒绝)。我花了几天时间才发现问题,并重新上传了几次到iTunes Connect。

现在我使用UIDevice.currentDevice().userInterfaceIdiom代替,我的应用程序可以幸免于这样的崩溃。

Swift 2.0 &iOS 9 &Xcode 7.1

// 1. request an UITraitCollection instance
let deviceIdiom = UIScreen.mainScreen().traitCollection.userInterfaceIdiom


// 2. check the idiom
switch (deviceIdiom) {


case .Pad:
print("iPad style UI")
case .Phone:
print("iPhone and iPod touch style UI")
case .TV:
print("tvOS style UI")
default:
print("Unspecified UI idiom")


}

Swift 3.0和Swift 4.0

// 1. request an UITraitCollection instance
let deviceIdiom = UIScreen.main.traitCollection.userInterfaceIdiom


// 2. check the idiom
switch (deviceIdiom) {


case .pad:
print("iPad style UI")
case .phone:
print("iPhone and iPod touch style UI")
case .tv:
print("tvOS style UI")
default:
print("Unspecified UI idiom")
}
< p > UITraitCollection使用。 iOS特征环境是通过UITraitEnvironment协议的traitCollection属性公开的。以下类采用此协议:

  • UIScreen
  • ui窗口
  • ui
  • UIPresentationController
  • UIView

Swift 2.0 &iOS 7+ / iOS 8+ / iOS 9+

public class Helper {
public class var isIpad:Bool {
if #available(iOS 8.0, *) {
return UIScreen.mainScreen().traitCollection.userInterfaceIdiom == .Pad
} else {
return UIDevice.currentDevice().userInterfaceIdiom == .Pad
}
}
public class var isIphone:Bool {
if #available(iOS 8.0, *) {
return UIScreen.mainScreen().traitCollection.userInterfaceIdiom == .Phone
} else {
return UIDevice.currentDevice().userInterfaceIdiom == .Phone
}
}
}

使用:

if Helper.isIpad {


}

guard Helper.isIpad else {
return
}

由于@user3378170

斯威夫特2. x:

添加到Beslav Turalov的回答的新条目iPad Pro可以很容易地通过这一行找到

检测iPad Pro

struct DeviceType
{
...
static let IS_IPAD_PRO = UIDevice.currentDevice().userInterfaceIdiom == .Pad && ScreenSize.SCREEN_MAX_LENGTH == 1366.0
}

Swift 3(电视和汽车添加):

struct ScreenSize
{
static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}


struct DeviceType
{
static let IS_IPHONE            = UIDevice.current.userInterfaceIdiom == .phone
static let IS_IPHONE_4_OR_LESS  = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0
static let IS_IPHONE_5          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0
static let IS_IPHONE_6          = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0
static let IS_IPHONE_6P         = UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0
static let IS_IPHONE_7          = IS_IPHONE_6
static let IS_IPHONE_7P         = IS_IPHONE_6P
static let IS_IPAD              = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0
static let IS_IPAD_PRO_9_7      = IS_IPAD
static let IS_IPAD_PRO_12_9     = UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1366.0
static let IS_TV                = UIDevice.current.userInterfaceIdiom == .tv
static let IS_CAR_PLAY          = UIDevice.current.userInterfaceIdiom == .carPlay
}


struct Version{
static let SYS_VERSION_FLOAT = (UIDevice.current.systemVersion as NSString).floatValue
static let iOS7 = (Version.SYS_VERSION_FLOAT < 8.0 && Version.SYS_VERSION_FLOAT >= 7.0)
static let iOS8 = (Version.SYS_VERSION_FLOAT >= 8.0 && Version.SYS_VERSION_FLOAT < 9.0)
static let iOS9 = (Version.SYS_VERSION_FLOAT >= 9.0 && Version.SYS_VERSION_FLOAT < 10.0)
static let iOS10 = (Version.SYS_VERSION_FLOAT >= 10.0 && Version.SYS_VERSION_FLOAT < 11.0)
}

使用:

if DeviceType.IS_IPHONE_7P { print("iPhone 7 plus") }
if DeviceType.IS_IPAD_PRO_9_7 && Version.iOS10 { print("iPad pro 9.7 with iOS 10 version") }

如果你想检查当前设备是iPad还是iPhone,那么你可以使用这些代码行:

 if(UIDevice.currentDevice().userInterfaceIdiom == .Pad){


}else if(UIDevice.currentDevice().userInterfaceIdiom == .Phone){


}

尝试添加这样的扩展:

    public extension UIDevice {


var modelName: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 where value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}


switch identifier {
case "iPod5,1":                                 return "iPod Touch 5"
case "iPod7,1":                                 return "iPod Touch 6"
case "iPhone3,1", "iPhone3,2", "iPhone3,3":     return "iPhone 4"
case "iPhone4,1":                               return "iPhone 4s"
case "iPhone5,1", "iPhone5,2":                  return "iPhone 5"
case "iPhone5,3", "iPhone5,4":                  return "iPhone 5c"
case "iPhone6,1", "iPhone6,2":                  return "iPhone 5s"
case "iPhone7,2":                               return "iPhone 6"
case "iPhone7,1":                               return "iPhone 6 Plus"
case "iPhone8,1":                               return "iPhone 6s"
case "iPhone8,2":                               return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3":                  return "iPhone 7"
case "iPhone9,2", "iPhone9,4":                  return "iPhone 7 Plus"
case "iPhone8,4":                               return "iPhone SE"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3":           return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6":           return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3":           return "iPad Air"
case "iPad5,3", "iPad5,4":                      return "iPad Air 2"
case "iPad2,5", "iPad2,6", "iPad2,7":           return "iPad Mini"
case "iPad4,4", "iPad4,5", "iPad4,6":           return "iPad Mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9":           return "iPad Mini 3"
case "iPad5,1", "iPad5,2":                      return "iPad Mini 4"
case "iPad6,3", "iPad6,4", "iPad6,7", "iPad6,8":return "iPad Pro"
case "AppleTV5,3":                              return "Apple TV"
case "i386", "x86_64":                          return "Simulator"
default:                                        return identifier
}
}


}

下面是你如何使用它:

let modelName = UIDevice.currentDevice().modelName

<强>编辑 对于模拟器,您可以尝试解决方案在这里

斯威夫特3.0:

let userInterface = UIDevice.current.userInterfaceIdiom


if(userInterface == .pad){
//iPads
}else if(userInterface == .phone){
//iPhone
}else if(userInterface == .carPlay){
//CarPlay
}else if(userInterface == .tv){
//AppleTV
}

对上面的答案做了一些补充,以便返回一个类型而不是字符串值。

我认为这主要是用于UI调整,所以我不认为包括所有的子型号,如iPhone 5s,但这可以很容易地通过添加模型测试扩展到isDevice数组

在Swift 3.1 Xcode 8.3.2中使用物理和模拟器设备进行了测试

实现:

UIDevice.whichDevice()

public enum SVNDevice {
case isiPhone4, isIphone5, isIphone6or7, isIphone6por7p, isIphone, isIpad, isIpadPro
}


extension UIDevice {
class func whichDevice() -> SVNDevice? {
let isDevice = { (comparision: Array<(Bool, SVNDevice)>) -> SVNDevice? in
var device: SVNDevice?
comparision.forEach({
device = $0.0 ? $0.1 : device
})
return device
}


return isDevice([
(UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH < 568.0, SVNDevice.isiPhone4),
(UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 568.0, SVNDevice.isIphone5),
(UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 667.0, SVNDevice.isIphone6or7),
(UIDevice.current.userInterfaceIdiom == .phone && ScreenSize.SCREEN_MAX_LENGTH == 736.0, SVNDevice.isIphone6por7p),
(UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1024.0, SVNDevice.isIpad),
(UIDevice.current.userInterfaceIdiom == .pad && ScreenSize.SCREEN_MAX_LENGTH == 1366.0, SVNDevice.isIpadPro)])
}
}






private struct ScreenSize {
static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH, ScreenSize.SCREEN_HEIGHT)
}

我创建了一个名为SVNBootstaper的框架,其中包括这个和其他一些辅助协议,它是公共的,可以通过Carthage使用。

在swift 4 &Xcode 9.2,你可以通过以下方法来检测一个设备是否是iPhone/iPad。

if (UIDevice.current.userInterfaceIdiom == .pad){
print("iPad")
}
else{
print("iPhone")
}

另一种方式

    let deviceName = UIDevice.current.model
print(deviceName);
if deviceName == "iPhone"{
print("iPhone")
}
else{
print("iPad")
}

Swift 4.2 - 5.1扩展

 public extension UIDevice {


class var isPhone: Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}


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


class var isTV: Bool {
return UIDevice.current.userInterfaceIdiom == .tv
}


class var isCarPlay: Bool {
return UIDevice.current.userInterfaceIdiom == .carPlay
}
}

使用

if UIDevice.isPad {
// Do something
}

谢谢大家的支持:)

UIDevice + Extensions.swift

import Foundation
import UIKit


extension UIDevice {
static let modelName: String = {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}


func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity
#if os(iOS)
switch identifier {
case "iPod5,1":                                 return "iPod Touch 5"
case "iPod7,1":                                 return "iPod Touch 6"
case "iPhone3,1", "iPhone3,2", "iPhone3,3":     return "iPhone 4"
case "iPhone4,1":                               return "iPhone 4s"
case "iPhone5,1", "iPhone5,2":                  return "iPhone 5"
case "iPhone5,3", "iPhone5,4":                  return "iPhone 5c"
case "iPhone6,1", "iPhone6,2":                  return "iPhone 5s"
case "iPhone7,2":                               return "iPhone 6"
case "iPhone7,1":                               return "iPhone 6 Plus"
case "iPhone8,1":                               return "iPhone 6s"
case "iPhone8,2":                               return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3":                  return "iPhone 7"
case "iPhone9,2", "iPhone9,4":                  return "iPhone 7 Plus"
case "iPhone8,4":                               return "iPhone SE"
case "iPhone10,1", "iPhone10,4":                return "iPhone 8"
case "iPhone10,2", "iPhone10,5":                return "iPhone 8 Plus"
case "iPhone10,3", "iPhone10,6":                return "iPhone X"
case "iPhone11,2":                              return "iPhone XS"
case "iPhone11,4", "iPhone11,6":                return "iPhone XS Max"
case "iPhone11,8":                              return "iPhone XR"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3":           return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6":           return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3":           return "iPad Air"
case "iPad5,3", "iPad5,4":                      return "iPad Air 2"
case "iPad6,11", "iPad6,12":                    return "iPad 5"
case "iPad7,5", "iPad7,6":                      return "iPad 6"
case "iPad2,5", "iPad2,6", "iPad2,7":           return "iPad Mini"
case "iPad4,4", "iPad4,5", "iPad4,6":           return "iPad Mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9":           return "iPad Mini 3"
case "iPad5,1", "iPad5,2":                      return "iPad Mini 4"
case "iPad6,3", "iPad6,4":                      return "iPad Pro 9.7 Inch"
case "iPad6,7", "iPad6,8":                      return "iPad Pro 12.9 Inch"
case "iPad7,1", "iPad7,2":                      return "iPad Pro 12.9 Inch 2. Generation"
case "iPad7,3", "iPad7,4":                      return "iPad Pro 10.5 Inch"
case "AppleTV5,3":                              return "Apple TV"
case "AppleTV6,2":                              return "Apple TV 4K"
case "AudioAccessory1,1":                       return "HomePod"
case "i386", "x86_64":                          return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))"
default:                                        return identifier
}
#elseif os(tvOS)
switch identifier {
case "AppleTV5,3": return "Apple TV 4"
case "AppleTV6,2": return "Apple TV 4K"
case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))"
default: return identifier
}
#endif
}
return mapToDevice(identifier: identifier)
}()
}


enum DeviceName: String {
case iPod_Touch_5 = "iPod Touch 5"
case pod_Touch_6 = "Pod Touch 6"
case iPhone_4 = "iPhone 4"
case iPhone_4s = "iPhone 4s"
case iPhone_5 = "iPhone 5"
case iPhone_5c = "iPhone 5c"
case iPhone_5s = "iPhone 5s"
case iPhone_6 = "iPhone 6"
case iPhone_6_Plus = "iPhone 6 Plus"
case iPhone_6s = "iPhone 6s"
case iPhone_6s_Plus = "iPhone 6s Plus"
case iPhone_7 = "iPhone 7"
case iPhone_7_Plus = "iPhone 7 Plus"
case iPhone_SE = "iPhone SE"
case iPhone_8 = "iPhone 8"
case iPhone_8_Plus = "iPhone 8 Plus"
case iPhone_X = "iPhone X"
case iPhone_XS = "iPhone XS"
case iPhone_XS_Max = "iPhone XS Max"
case iPhone_XR = "iPhone XR"
case iPad_2 = "iPad 2"
case iPad_3 = "iPad 3"
case iPad_4 = "iPad 4"
case iPad_Air = "iPad Air"
case iPad_Air_2 = "iPad Air 2"
case iPad_5 = "iPad 5"
case iPad_6 = "iPad 6"
case iPad_Mini = "iPad Mini"
case iPad_Mini_2 = "iPad Mini 2"
case iPad_Mini_3 = "iPad Mini 3"
case iPad_Mini_4 = "iPad Mini 4"
case iPad_Pro_9_7_Inch = "iPad Pro 9.7 Inch"
case iPad_Pro_12_9_Inch = "iPad Pro 12.9 Inch"
case iPad_Pro_12_9_Inch_2_Generation = "iPad Pro 12.9 Inch 2. Generation"
case iPad_Pro_10_5_Inch = "iPad Pro 10.5 Inch"
case apple_TV = "Apple TV"
case apple_TV_4K = "Apple TV 4K"
case homePod = "HomePod"
}

SharedFunctions.swift

import Foundation
import UIKit
func isDevice(_ name: DeviceName) -> Bool {
let modelName = UIDevice.modelName.replacingOccurrences(of: "Simulator", with: "").trimmed()
if name.rawValue == modelName {
return true
}


return false
}

字符串+ Whitespace.swift

import Foundation


extension String {
public func trimmed() -> String {
return self.trimmingCharacters(in: .whitespacesAndNewlines)
}
}

试试这个检查当前设备是iPhone还是iPad:

斯威夫特5

struct Device {
static let IS_IPAD = UIDevice.current.userInterfaceIdiom == .pad
static let IS_IPHONE = UIDevice.current.userInterfaceIdiom == .phone
}

使用:

if(Device.IS_IPHONE){
// device is iPhone
}if(Device.IS_IPAD){
// device is iPad (or a Mac running under macOS Catalyst)
}else{
// other
}

自iOS 13以来,UI_USER_INTERFACE_IDIOM已弃用。如果你的代码仍然在Obj-C中,你可以使用以下方法:

if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
// device is iPad
}

地点:

typedef NS_ENUM(NSInteger, UIUserInterfaceIdiom) {
UIUserInterfaceIdiomUnspecified = -1,
UIUserInterfaceIdiomPhone API_AVAILABLE(ios(3.2)), // iPhone and iPod touch style UI
UIUserInterfaceIdiomPad API_AVAILABLE(ios(3.2)), // iPad style UI
UIUserInterfaceIdiomTV API_AVAILABLE(ios(9.0)), // Apple TV style UI
UIUserInterfaceIdiomCarPlay API_AVAILABLE(ios(9.0)), // CarPlay style UI
};

你可以在Swift 5上使用新的方式:

switch traitCollection.userInterfaceIdiom {
        

case .unspecified:
// do something
case .phone:
// do something
case .pad:
// do something
case .tv:
// do something
case .carPlay:
// do something
case .mac:
// do something
@unknown default:
// do something
}