有没有办法在Swift中获得设备型号名称(iPhone 4S, iPhone 5, iPhone 5S等)?

我知道有一个名为UIDevice.currentDevice()的属性。模型,但它只返回设备类型(iPod touch, iPhone, iPad, iPhone模拟器等)。

我也知道在Objective-C中使用以下方法可以轻松完成:

#import <sys/utsname.h>

struct utsname systemInfo;
uname(&systemInfo);

NSString* deviceModel = [NSString stringWithCString:systemInfo.machine
                          encoding:NSUTF8StringEncoding];

但是我正在Swift中开发我的iPhone应用程序,所以有人可以帮助我用等效的方法在Swift中解决这个问题吗?


当前回答

对于设备和模拟器, 创建一个名为UIDevice.swift的新swift文件

添加以下代码

import UIKit


public extension UIDevice {

var modelName: String {
    #if (arch(i386) || arch(x86_64)) && os(iOS)
        let DEVICE_IS_SIMULATOR = true
    #else
        let DEVICE_IS_SIMULATOR = false
    #endif

    var machineString : String = ""

    if DEVICE_IS_SIMULATOR == true
    {

        if let dir = NSProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
            machineString = dir
        }
    }
    else {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        machineString = 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 machineString {
    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 "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,7", "iPad6,8":                      return "iPad Pro"
    case "AppleTV5,3":                              return "Apple TV"
    default:                                        return machineString
    }
}
}

然后在你的视图控制器中,

 let deviceType = UIDevice.currentDevice().modelName

    if deviceType.lowercaseString.rangeOfString("iphone 4") != nil {
       print("iPhone 4 or iphone 4s")
    }
    else if deviceType.lowercaseString.rangeOfString("iphone 5") != nil {
        print("iPhone 5 or iphone 5s or iphone 5c")
    }
   else if deviceType.lowercaseString.rangeOfString("iphone 6") != nil {
        print("iPhone 6 Series")
    }

其他回答

以下是2023年1月更新的解决方案。包括最新的iPhone、iPad、Watch、iPod、Apple TV和HomePod:

extension UIDevice {
    
    static 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, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        switch identifier {
            // MARK: - iPhone
            case "i386": return "iPhone Simulator"
            case "x86_64": return "iPhone Simulator"
            case "arm64": return "iPhone Simulator"
            case "iPhone1,1": return "iPhone"
            case "iPhone1,2": return "iPhone 3G"
            case "iPhone2,1": return "iPhone 3GS"
            case "iPhone3,1": return "iPhone 4"
            case "iPhone3,2": return "iPhone 4 GSM Rev A"
            case "iPhone3,3": return "iPhone 4 CDMA"
            case "iPhone4,1": return "iPhone 4S"
            case "iPhone5,1": return "iPhone 5 (GSM)"
            case "iPhone5,2": return "iPhone 5 (GSM+CDMA)"
            case "iPhone5,3": return "iPhone 5C (GSM)"
            case "iPhone5,4": return "iPhone 5C (Global)"
            case "iPhone6,1": return "iPhone 5S (GSM)"
            case "iPhone6,2": return "iPhone 5S (Global)"
            case "iPhone7,1": return "iPhone 6 Plus"
            case "iPhone7,2": return "iPhone 6"
            case "iPhone8,1": return "iPhone 6s"
            case "iPhone8,2": return "iPhone 6s Plus"
            case "iPhone8,4": return "iPhone SE (GSM)"
            case "iPhone9,1": return "iPhone 7"
            case "iPhone9,2": return "iPhone 7 Plus"
            case "iPhone9,3": return "iPhone 7"
            case "iPhone9,4": return "iPhone 7 Plus"
            case "iPhone10,1": return "iPhone 8"
            case "iPhone10,2": return "iPhone 8 Plus"
            case "iPhone10,3": return "iPhone X Global"
            case "iPhone10,4": return "iPhone 8"
            case "iPhone10,5": return "iPhone 8 Plus"
            case "iPhone10,6": return "iPhone X GSM"
            case "iPhone11,2": return "iPhone XS"
            case "iPhone11,4": return "iPhone XS Max"
            case "iPhone11,6": return "iPhone XS Max Global"
            case "iPhone11,8": return "iPhone XR"
            case "iPhone12,1": return "iPhone 11"
            case "iPhone12,3": return "iPhone 11 Pro"
            case "iPhone12,5": return "iPhone 11 Pro Max"
            case "iPhone12,8": return "iPhone SE 2nd Gen"
            case "iPhone13,1": return "iPhone 12 Mini"
            case "iPhone13,2": return "iPhone 12"
            case "iPhone13,3": return "iPhone 12 Pro"
            case "iPhone13,4": return "iPhone 12 Pro Max"
            case "iPhone14,2": return "iPhone 13 Pro"
            case "iPhone14,3": return "iPhone 13 Pro Max"
            case "iPhone14,4": return "iPhone 13 Mini"
            case "iPhone14,5": return "iPhone 13"
            case "iPhone14,6": return "iPhone SE 3rd Gen"
            case "iPhone14,7": return "iPhone 14"
            case "iPhone14,8": return "iPhone 14 Plus"
            case "iPhone15,2": return "iPhone 14 Pro"
            case "iPhone15,3": return "iPhone 14 Pro Max"
            
            // MARK: - iPod
            case "iPod1,1": return "1st Gen iPod"
            case "iPod2,1": return "2nd Gen iPod"
            case "iPod3,1": return "3rd Gen iPod"
            case "iPod4,1": return "4th Gen iPod"
            case "iPod5,1": return "5th Gen iPod"
            case "iPod7,1": return "6th Gen iPod"
            case "iPod9,1": return "7th Gen iPod"
            
            // MARK: - iPad
            case "iPad1,1": return "iPad"
            case "iPad1,2": return "iPad 3G"
            case "iPad2,1": return "2nd Gen iPad"
            case "iPad2,2": return "2nd Gen iPad GSM"
            case "iPad2,3": return "2nd Gen iPad CDMA"
            case "iPad2,4": return "2nd Gen iPad New Revision"
            case "iPad3,1": return "3rd Gen iPad"
            case "iPad3,2": return "3rd Gen iPad CDMA"
            case "iPad3,3": return "3rd Gen iPad GSM"
            case "iPad2,5": return "iPad mini"
            case "iPad2,6": return "iPad mini GSM+LTE"
            case "iPad2,7": return "iPad mini CDMA+LTE"
            case "iPad3,4": return "4th Gen iPad"
            case "iPad3,5": return "4th Gen iPad GSM+LTE"
            case "iPad3,6": return "4th Gen iPad CDMA+LTE"
            case "iPad4,1": return "iPad Air (WiFi)"
            case "iPad4,2": return "iPad Air (GSM+CDMA)"
            case "iPad4,3": return "1st Gen iPad Air (China)"
            case "iPad4,4": return "iPad mini Retina (WiFi)"
            case "iPad4,5": return "iPad mini Retina (GSM+CDMA)"
            case "iPad4,6": return "iPad mini Retina (China)"
            case "iPad4,7": return "iPad mini 3 (WiFi)"
            case "iPad4,8": return "iPad mini 3 (GSM+CDMA)"
            case "iPad4,9": return "iPad Mini 3 (China)"
            case "iPad5,1": return "iPad mini 4 (WiFi)"
            case "iPad5,2": return "4th Gen iPad mini (WiFi+Cellular)"
            case "iPad5,3": return "iPad Air 2 (WiFi)"
            case "iPad5,4": return "iPad Air 2 (Cellular)"
            case "iPad6,3": return "iPad Pro (9.7 inch, WiFi)"
            case "iPad6,4": return "iPad Pro (9.7 inch, WiFi+LTE)"
            case "iPad6,7": return "iPad Pro (12.9 inch, WiFi)"
            case "iPad6,8": return "iPad Pro (12.9 inch, WiFi+LTE)"
            case "iPad6,11": return "iPad (2017)"
            case "iPad6,12": return "iPad (2017)"
            case "iPad7,1": return "iPad Pro 2nd Gen (WiFi)"
            case "iPad7,2": return "iPad Pro 2nd Gen (WiFi+Cellular)"
            case "iPad7,3": return "iPad Pro 10.5-inch 2nd Gen"
            case "iPad7,4": return "iPad Pro 10.5-inch 2nd Gen"
            case "iPad7,5": return "iPad 6th Gen (WiFi)"
            case "iPad7,6": return "iPad 6th Gen (WiFi+Cellular)"
            case "iPad7,11": return "iPad 7th Gen 10.2-inch (WiFi)"
            case "iPad7,12": return "iPad 7th Gen 10.2-inch (WiFi+Cellular)"
            case "iPad8,1": return "iPad Pro 11 inch 3rd Gen (WiFi)"
            case "iPad8,2": return "iPad Pro 11 inch 3rd Gen (1TB, WiFi)"
            case "iPad8,3": return "iPad Pro 11 inch 3rd Gen (WiFi+Cellular)"
            case "iPad8,4": return "iPad Pro 11 inch 3rd Gen (1TB, WiFi+Cellular)"
            case "iPad8,5": return "iPad Pro 12.9 inch 3rd Gen (WiFi)"
            case "iPad8,6": return "iPad Pro 12.9 inch 3rd Gen (1TB, WiFi)"
            case "iPad8,7": return "iPad Pro 12.9 inch 3rd Gen (WiFi+Cellular)"
            case "iPad8,8": return "iPad Pro 12.9 inch 3rd Gen (1TB, WiFi+Cellular)"
            case "iPad8,9": return "iPad Pro 11 inch 4th Gen (WiFi)"
            case "iPad8,10": return "iPad Pro 11 inch 4th Gen (WiFi+Cellular)"
            case "iPad8,11": return "iPad Pro 12.9 inch 4th Gen (WiFi)"
            case "iPad8,12": return "iPad Pro 12.9 inch 4th Gen (WiFi+Cellular)"
            case "iPad11,1": return "iPad mini 5th Gen (WiFi)"
            case "iPad11,2": return "iPad mini 5th Gen"
            case "iPad11,3": return "iPad Air 3rd Gen (WiFi)"
            case "iPad11,4": return "iPad Air 3rd Gen"
            case "iPad11,6": return "iPad 8th Gen (WiFi)"
            case "iPad11,7": return "iPad 8th Gen (WiFi+Cellular)"
            case "iPad12,1": return "iPad 9th Gen (WiFi)"
            case "iPad12,2": return "iPad 9th Gen (WiFi+Cellular)"
            case "iPad14,1": return "iPad mini 6th Gen (WiFi)"
            case "iPad14,2": return "iPad mini 6th Gen (WiFi+Cellular)"
            case "iPad13,1": return "iPad Air 4th Gen (WiFi)"
            case "iPad13,2": return "iPad Air 4th Gen (WiFi+Cellular)"
            case "iPad13,4": return "iPad Pro 11 inch 5th Gen"
            case "iPad13,5": return "iPad Pro 11 inch 5th Gen"
            case "iPad13,6": return "iPad Pro 11 inch 5th Gen"
            case "iPad13,7": return "iPad Pro 11 inch 5th Gen"
            case "iPad13,8": return "iPad Pro 12.9 inch 5th Gen"
            case "iPad13,9": return "iPad Pro 12.9 inch 5th Gen"
            case "iPad13,10": return "iPad Pro 12.9 inch 5th Gen"
            case "iPad13,11": return "iPad Pro 12.9 inch 5th Gen"
            case "iPad13,16": return "iPad Air 5th Gen (WiFi)"
            case "iPad13,17": return "iPad Air 5th Gen (WiFi+Cellular)"
            case "iPad13,18": return "iPad 10th Gen"
            case "iPad13,19": return "iPad 10th Gen"
            case "iPad14,3": return "iPad Pro 11 inch 4th Gen"
            case "iPad14,4": return "iPad Pro 11 inch 4th Gen"
            case "iPad14,5": return "iPad Pro 12.9 inch 6th Gen"
            case "iPad14,6": return "iPad Pro 12.9 inch 6th Gen"
            
            // MARK: - Watch
            case "Watch1,1": return "Apple Watch 38mm case"
            case "Watch1,2": return "Apple Watch 42mm case"
            case "Watch2,6": return "Apple Watch Series 1 38mm case"
            case "Watch2,7": return "Apple Watch Series 1 42mm case"
            case "Watch2,3": return "Apple Watch Series 2 38mm case"
            case "Watch2,4": return "Apple Watch Series 2 42mm case"
            case "Watch3,1": return "Apple Watch Series 3 38mm case (GPS+Cellular)"
            case "Watch3,2": return "Apple Watch Series 3 42mm case (GPS+Cellular)"
            case "Watch3,3": return "Apple Watch Series 3 38mm case (GPS)"
            case "Watch3,4": return "Apple Watch Series 3 42mm case (GPS)"
            case "Watch4,1": return "Apple Watch Series 4 40mm case (GPS)"
            case "Watch4,2": return "Apple Watch Series 4 44mm case (GPS)"
            case "Watch4,3": return "Apple Watch Series 4 40mm case (GPS+Cellular)"
            case "Watch4,4": return "Apple Watch Series 4 44mm case (GPS+Cellular)"
            case "Watch5,1": return "Apple Watch Series 5 40mm case (GPS)"
            case "Watch5,2": return "Apple Watch Series 5 44mm case (GPS)"
            case "Watch5,3": return "Apple Watch Series 5 40mm case (GPS+Cellular)"
            case "Watch5,4": return "Apple Watch Series 5 44mm case (GPS+Cellular)"
            case "Watch5,9": return "Apple Watch SE 40mm case (GPS)"
            case "Watch5,10": return "Apple Watch SE 44mm case (GPS)"
            case "Watch5,11": return "Apple Watch SE 40mm case (GPS+Cellular)"
            case "Watch5,12": return "Apple Watch SE 44mm case (GPS+Cellular)"
            case "Watch6,1": return "Apple Watch Series 6 40mm case (GPS)"
            case "Watch6,2": return "Apple Watch Series 6 44mm case (GPS)"
            case "Watch6,3": return "Apple Watch Series 6 40mm case (GPS+Cellular)"
            case "Watch6,4": return "Apple Watch Series 6 44mm case (GPS+Cellular)"
            case "Watch6,6": return "Apple Watch Series 7 41mm case (GPS)"
            case "Watch6,7": return "Apple Watch Series 7 45mm case (GPS)"
            case "Watch6,8": return "Apple Watch Series 7 41mm case (GPS+Cellular)"
            case "Watch6,9": return "Apple Watch Series 7 45mm case (GPS+Cellular)"
            case "Watch6,10": return "Apple Watch SE 40mm case (GPS)"
            case "Watch6,11": return "Apple Watch SE 44mm case (GPS)"
            case "Watch6,12": return "Apple Watch SE 40mm case (GPS+Cellular)"
            case "Watch6,13": return "Apple Watch SE 44mm case (GPS+Cellular)"
            case "Watch6,14": return "Apple Watch Series 8 41mm case (GPS)"
            case "Watch6,15": return "Apple Watch Series 8 45mm case (GPS)"
            case "Watch6,16": return "Apple Watch Series 8 41mm case (GPS+Cellular)"
            case "Watch6,17": return "Apple Watch Series 8 45mm case (GPS+Cellular)"
            case "Watch6,18": return "Apple Watch Ultra"
            
            // MARK: - Apple TV
            case "AppleTV5,3": return "Apple TV"
            case "AppleTV6,2": return "Apple TV 4K"
            
            // MARK: - HomePod
            case "AudioAccessory1,1": return "HomePod"
            case "AudioAccessory5,1": return "HomePod mini"
            
            // MARK: - Unrecognized
            default: return identifier
        }
    }
}

用法:

UIDevice.modelName

维基设备

异步库,从iphonewiki给你答案

A crazy little experiment for automation fans like me. I made this algorithm that reads the identification code of the device, physical or simulated, and load the theiphonewiki page to extrapolate the model name based on the identification code (example iPhone11,2 -> iPhone XS). The algorithm interfaces with the WIKI page using the internal Wiki API Sandbox tool that allows you to have a JSON response, however the content is not obtainable in JSON (just the part that was needed, that is the wikitables) so I parsed the HTML content to get to the device name, without using third parts HTML parsing libraries.

优点:总是更新,你不需要添加新的设备

缺点:异步回答使用维基页面从网络

附注:请随意改进我的代码,以获得更精确的结果和更优雅的语法 P.S.S.如果你需要更直接的答案,请使用我之前在本页的答案

public extension UIDevice {
    var identifier: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let modelCode = withUnsafePointer(to: &systemInfo.machine) {
            $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                ptr in String.init(validatingUTF8: ptr)
            }
        }
        if modelCode == "x86_64" {
            if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
                if let simMap = String(validatingUTF8: simModelCode) {
                    return simMap
                }
            }
        }
        return modelCode ?? "?unrecognized?"
    }
}
class WikiDevice {
    static func model(_ completion: @escaping ((String) -> ())){
        let unrecognized = "?unrecognized?"
        guard let wikiUrl=URL(string:"https://www.theiphonewiki.com//w/api.php?action=parse&format=json&page=Models") else { return completion(unrecognized) }
        var identifier: String {
            var systemInfo = utsname()
            uname(&systemInfo)
            let modelCode = withUnsafePointer(to: &systemInfo.machine) {
                $0.withMemoryRebound(to: CChar.self, capacity: 1) {
                    ptr in String.init(validatingUTF8: ptr)
                }
            }
            if modelCode == "x86_64" {
                if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
                    if let simMap = String(validatingUTF8: simModelCode) {
                        return simMap
                    }
                }
            }
            return modelCode ?? unrecognized
        }
        guard identifier != unrecognized else { return completion(unrecognized)}
        let request = URLRequest(url: wikiUrl)
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            do {
                guard let data = data,
                    let response = response as? HTTPURLResponse, (200 ..< 300) ~= response.statusCode,
                    error == nil else { return completion(unrecognized) }
                guard let convertedString = String(data: data, encoding: String.Encoding.utf8) else { return completion(unrecognized) }
                var wikiTables = convertedString.components(separatedBy: "wikitable")
                wikiTables.removeFirst()
                var tables = [[String]]()
                wikiTables.enumerated().forEach{ index,table in
                    let rawRows = table.components(separatedBy: #"<tr>\n<td"#)
                    var counter = 0
                    var rows = [String]()
                    while counter < rawRows.count {
                        let rawRow = rawRows[counter]
                        if let subRowsNum = rawRow.components(separatedBy: #"rowspan=\""#).dropFirst().compactMap({ sub in
                            (sub.range(of: #"\">"#)?.lowerBound).flatMap { endRange in
                                String(sub[sub.startIndex ..< endRange])
                            }
                        }).first {
                            if let subRowsTot = Int(subRowsNum) {
                                var otherRows = ""
                                for i in counter..<counter+subRowsTot {
                                    otherRows += rawRows[i]
                                }
                                let row = rawRow + otherRows
                                rows.append(row)
                                counter += subRowsTot-1
                            }
                        } else {
                            rows.append(rawRows[counter])
                        }
                        counter += 1
                    }
                    tables.append(rows)
                }
                for table in tables {
                    if let rowIndex = table.firstIndex(where: {$0.lowercased().contains(identifier.lowercased())}) {
                        let rows = table[rowIndex].components(separatedBy: "<td>")
                        if rows.count>0 {
                            if rows[0].contains("title") { //hyperlink
                                if let (cleanedGen) = rows[0].components(separatedBy: #">"#).dropFirst().compactMap({ sub in
                                    (sub.range(of: "</")?.lowerBound).flatMap { endRange in
                                        String(sub[sub.startIndex ..< endRange]).replacingOccurrences(of: #"\n"#, with: "")
                                    }
                                }).first {
                                    completion(cleanedGen)
                                }
                            } else {
                                let raw = rows[0].replacingOccurrences(of: "<td>", with: "")
                                let cleanedGen = raw.replacingOccurrences(of: #"\n"#, with: "")
                                completion(cleanedGen)
                            }
                            return
                        }
                    }
                }
                completion(unrecognized)
            }
        }.resume()
    }
}

用法:

var deviceModel:String = ""
WikiDevice.model { (model) in
     print("Using WikiDevice, running on: \(model)")
     deviceModel = model
}

输出:

Using WikiDevice, running on: iPhone 11 Pro Max

GitHUB:

如果您需要测试这个库,您可以从这里下载测试项目

我的简单解决方案是按设备分组,支持新设备iPhone 8和iPhone X在Swift 3:

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, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        switch identifier {
        case "iPhone3,1", "iPhone3,2", "iPhone3,3", "iPhone4,1":
            return "iPhone 4"

        case "iPhone5,1", "iPhone5,2", "iPhone5,3", "iPhone5,4", "iPhone6,1", "iPhone6,2", "iPhone8,4":
            return "iPhone 5"

        case "iPhone7,2", "iPhone8,1", "iPhone9,1", "iPhone9,3", "iPhone10,1", "iPhone10,4":
            return "iPhone 6,7,8"

        case "iPhone7,1", "iPhone8,2", "iPhone9,2", "iPhone9,4", "iPhone10,2", "iPhone10,5":
            return "iPhone Plus"

        case "iPhone10,3", "iPhone10,6":
            return "iPhone X"

        case "i386", "x86_64":
            return "Simulator"
        default:
            return identifier
        }
    }
}

和使用:

switch UIDevice.current.modelName {
  case "iPhone 4":
  case "iPhone 5":
  case "iPhone 6,7,8":
  case "iPhone Plus":
  case "iPhone X":
  case "Simulator":
  default:
}

基于这个答案和这个答案。我创造了一个公共主旨

如何使用它

let boolean: Bool = UIDevice.isDevice(ofType: .iPhoneX)
// true or false

let specificDevice: DeviceModel.Model = UIDevice.modelType
// iPhone6s, iPhoneX, iPad etc...

let model: DeviceModel = UIDevice.model
// .simulator(let specificDevice), .real(let specificDevice),
// .unrecognizedSimulator(let string), .unrecognized(let string)

let modelName: String = UIDevice.model.name
// iPhone 6, iPhone X, etc...

这是要点里面的代码

public extension UIDevice {
    public static var modelCode: String {
        if let simulatorModelIdentifier = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { return simulatorModelIdentifier }
        var systemInfo = utsname()
        uname(&systemInfo)
        return withUnsafeMutablePointer(to: &systemInfo.machine) {
            ptr in String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
        }
    }

    public static var model: DeviceModel {
        // Thanks https://stackoverflow.com/a/26962452/5928180
        var systemInfo = utsname()
        uname(&systemInfo)
        let modelCode = withUnsafeMutablePointer(to: &systemInfo.machine) {
            ptr in String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
        }

        // Thanks https://stackoverflow.com/a/33495869/5928180
        if modelCode == "i386" || modelCode == "x86_64" {
            if let simulatorModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"], let model = DeviceModel.Model(modelCode: simulatorModelCode) {
                return DeviceModel.simulator(model)
            } else if let simulatorModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] {
                return DeviceModel.unrecognizedSimulator(simulatorModelCode)
            } else {
                return DeviceModel.unrecognized(modelCode)
            }
        } else if let model = DeviceModel.Model(modelCode: modelCode) {
            return DeviceModel.real(model)
        } else {
            return DeviceModel.unrecognized(modelCode)
        }
    }

    public static var modelType: DeviceModel.Model? {
        return UIDevice.model.model
    }

    public static func isDevice(ofType model: DeviceModel.Model) -> Bool {
        return UIDevice.modelType == model
    }
}


public enum DeviceModel {
    case simulator(Model)
    case unrecognizedSimulator(String)
    case real(Model)
    case unrecognized(String)

    public enum Model: String {
        case iPod1            = "iPod 1"
        case iPod2            = "iPod 2"
        case iPod3            = "iPod 3"
        case iPod4            = "iPod 4"
        case iPod5            = "iPod 5"
        case iPad2            = "iPad 2"
        case iPad3            = "iPad 3"
        case iPad4            = "iPad 4"
        case iPhone4          = "iPhone 4"
        case iPhone4S         = "iPhone 4S"
        case iPhone5          = "iPhone 5"
        case iPhone5S         = "iPhone 5S"
        case iPhone5C         = "iPhone 5C"
        case iPadMini1        = "iPad Mini 1"
        case iPadMini2        = "iPad Mini 2"
        case iPadMini3        = "iPad Mini 3"
        case iPadAir1         = "iPad Air 1"
        case iPadAir2         = "iPad Air 2"
        case iPadPro9_7       = "iPad Pro 9.7\""
        case iPadPro9_7_cell  = "iPad Pro 9.7\" cellular"
        case iPadPro10_5      = "iPad Pro 10.5\""
        case iPadPro10_5_cell = "iPad Pro 10.5\" cellular"
        case iPadPro12_9      = "iPad Pro 12.9\""
        case iPadPro12_9_cell = "iPad Pro 12.9\" cellular"
        case iPhone6          = "iPhone 6"
        case iPhone6plus      = "iPhone 6 Plus"
        case iPhone6S         = "iPhone 6S"
        case iPhone6Splus     = "iPhone 6S Plus"
        case iPhoneSE         = "iPhone SE"
        case iPhone7          = "iPhone 7"
        case iPhone7plus      = "iPhone 7 Plus"
        case iPhone8          = "iPhone 8"
        case iPhone8plus      = "iPhone 8 Plus"
        case iPhoneX          = "iPhone X"

        init?(modelCode: String) {
            switch modelCode {
            case "iPod1,1":    self = .iPod1
            case "iPod2,1":    self = .iPod2
            case "iPod3,1":    self = .iPod3
            case "iPod4,1":    self = .iPod4
            case "iPod5,1":    self = .iPod5
            case "iPad2,1":    self = .iPad2
            case "iPad2,2":    self = .iPad2
            case "iPad2,3":    self = .iPad2
            case "iPad2,4":    self = .iPad2
            case "iPad2,5":    self = .iPadMini1
            case "iPad2,6":    self = .iPadMini1
            case "iPad2,7":    self = .iPadMini1
            case "iPhone3,1":  self = .iPhone4
            case "iPhone3,2":  self = .iPhone4
            case "iPhone3,3":  self = .iPhone4
            case "iPhone4,1":  self = .iPhone4S
            case "iPhone5,1":  self = .iPhone5
            case "iPhone5,2":  self = .iPhone5
            case "iPhone5,3":  self = .iPhone5C
            case "iPhone5,4":  self = .iPhone5C
            case "iPad3,1":    self = .iPad3
            case "iPad3,2":    self = .iPad3
            case "iPad3,3":    self = .iPad3
            case "iPad3,4":    self = .iPad4
            case "iPad3,5":    self = .iPad4
            case "iPad3,6":    self = .iPad4
            case "iPhone6,1":  self = .iPhone5S
            case "iPhone6,2":  self = .iPhone5S
            case "iPad4,1":    self = .iPadAir1
            case "iPad4,2":    self = .iPadAir2
            case "iPad4,4":    self = .iPadMini2
            case "iPad4,5":    self = .iPadMini2
            case "iPad4,6":    self = .iPadMini2
            case "iPad4,7":    self = .iPadMini3
            case "iPad4,8":    self = .iPadMini3
            case "iPad4,9":    self = .iPadMini3
            case "iPad6,3":    self = .iPadPro9_7
            case "iPad6,11":   self = .iPadPro9_7
            case "iPad6,4":    self = .iPadPro9_7_cell
            case "iPad6,12":   self = .iPadPro9_7_cell
            case "iPad6,7":    self = .iPadPro12_9
            case "iPad6,8":    self = .iPadPro12_9_cell
            case "iPad7,3":    self = .iPadPro10_5
            case "iPad7,4":    self = .iPadPro10_5_cell
            case "iPhone7,1":  self = .iPhone6plus
            case "iPhone7,2":  self = .iPhone6
            case "iPhone8,1":  self = .iPhone6S
            case "iPhone8,2":  self = .iPhone6Splus
            case "iPhone8,4":  self = .iPhoneSE
            case "iPhone9,1":  self = .iPhone7
            case "iPhone9,2":  self = .iPhone7plus
            case "iPhone9,3":  self = .iPhone7
            case "iPhone9,4":  self = .iPhone7plus
            case "iPhone10,1": self = .iPhone8
            case "iPhone10,2": self = .iPhone8plus
            case "iPhone10,3": self = .iPhoneX
            case "iPhone10,6": self = .iPhoneX
            default:           return nil
            }
        }
    }

    public var name: String {
        switch self {
        case .simulator(let model):         return "Simulator[\(model.rawValue)]"
        case .unrecognizedSimulator(let s): return "UnrecognizedSimulator[\(s)]"
        case .real(let model):              return model.rawValue
        case .unrecognized(let s):          return "Unrecognized[\(s)]"
        }
    }

    public var model: DeviceModel.Model? {
        switch self {
        case .simulator(let model):         return model
        case .real(let model):              return model
        case .unrecognizedSimulator(_):     return nil
        case .unrecognized(_):              return nil
        }
    }
}
extension UIDevice {

    public static let hardwareModel: String = {
        var path = [CTL_HW, HW_MACHINE]
        var n = 0
        sysctl(&path, 2, nil, &n, nil, 0)
        var a: [UInt8] = .init(repeating: 0, count: n)
        sysctl(&path, 2, &a, &n, nil, 0)
        return .init(cString: a)
    }()
}

UIDevice.hardwareModel // → iPhone9,3