I was wondering if it's possible to determine what kind of iPhone (for example) the currentdevice is? I know it's possible to get the model through NSString *deviceType = [[UIDevice currentDevice] model]; which will just return whether I have an "iPhone" or an "iPod", BUT I was wondering if it's possible to detect/know if I have an iPhone 3GS vs. and iPhone 4 vs. an iPhone 4S (in actuality, all I really want to do is determine if I have a 3G or not, because I'm doing fairly graphics intensive stuff).

所以,请告诉我,谢谢!


当前回答

如果你有一个plist设备(例如在https://stackoverflow.com/a/17655825/849616中由@Tib维护)来处理Swift 3,你会使用:

extension UIDevice {
    /// Fetches the information about the name of the device.
    ///
    /// - Returns: Should return meaningful device name, if not found will return device system code.
    public static func modelName() -> String {
        let physicalName = deviceSystemCode()
        if let deviceTypes = deviceTypes(), let modelName = deviceTypes[physicalName] as? String {
            return modelName
        }
        return physicalName
    }
}

private extension UIDevice {
    /// Fetches from system the code of the device
    static func deviceSystemCode() -> 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)))
        }
        return identifier
    }

    /// Fetches the plist entries from plist maintained in https://stackoverflow.com/a/17655825/849616
    ///
    /// - Returns: A dictionary with pairs of deviceSystemCode <-> meaningfulDeviceName.
    static func deviceTypes() -> NSDictionary? {
        if let fileUrl = Bundle.main.url(forResource: "your plist name", withExtension: "plist"),
            let configurationDictionary = NSDictionary(contentsOf: fileUrl) {
            return configurationDictionary
        }
        return nil
    }
}

稍后您可以使用UIDevice.modelName()调用它。

额外的荣誉归于@Tib(用于plist), @Aniruddh Joshi(用于deviceSystemCode()函数)。

其他回答

一个从NSString描述中脱离的类别

通常,在整个代码中避免任意的字符串比较是可取的。最好在一个地方更新字符串,并在应用程序中隐藏神奇的字符串。为此,我在UIDevice上提供了一个类别。

对于我的特定需求,我需要知道我正在使用的设备,而不需要知道可以通过其他方式轻松检索的网络功能的细节。因此,您将发现一个比不断增长的设备列表更粗粒度的枚举。

更新就是将设备添加到枚举和查找表中。

UIDevice + NTNUExtensions.h

typedef NS_ENUM(NSUInteger, NTNUDeviceType) {
    DeviceAppleUnknown,
    DeviceAppleSimulator,
    DeviceAppleiPhone,
    DeviceAppleiPhone3G,
    DeviceAppleiPhone3GS,
    DeviceAppleiPhone4,
    DeviceAppleiPhone4S,
    DeviceAppleiPhone5,
    DeviceAppleiPhone5C,
    DeviceAppleiPhone5S,
    DeviceAppleiPhone6,
    DeviceAppleiPhone6_Plus,
    DeviceAppleiPhone6S,
    DeviceAppleiPhone6S_Plus,
    DeviceAppleiPhoneSE,
    DeviceAppleiPhone7,
    DeviceAppleiPhone7_Plus,
    DeviceAppleiPodTouch,
    DeviceAppleiPodTouch2G,
    DeviceAppleiPodTouch3G,
    DeviceAppleiPodTouch4G,
    DeviceAppleiPad,
    DeviceAppleiPad2,
    DeviceAppleiPad3G,
    DeviceAppleiPad4G,
    DeviceAppleiPad5G_Air,
    DeviceAppleiPadMini,
    DeviceAppleiPadMini2G,
    DeviceAppleiPadPro12,
    DeviceAppleiPadPro9
};



@interface UIDevice (NTNUExtensions)

- (NSString *)ntnu_deviceDescription;
- (NTNUDeviceType)ntnu_deviceType;

@end

UIDevice + NTNUExtensions.m

#import <sys/utsname.h>
#import "UIDevice+NTNUExtensions.h"

@implementation UIDevice (NTNUExtensions)

- (NSString *)ntnu_deviceDescription
{
    struct utsname systemInfo;
    uname(&systemInfo);

    return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}

- (NTNUDeviceType)ntnu_deviceType
{
    NSNumber *deviceType = [[self ntnu_deviceTypeLookupTable] objectForKey:[self ntnu_deviceDescription]];
    return [deviceType unsignedIntegerValue];
}

- (NSDictionary *)ntnu_deviceTypeLookupTable
{
    return @{
             @"i386": @(DeviceAppleSimulator),
             @"x86_64": @(DeviceAppleSimulator),
             @"iPod1,1": @(DeviceAppleiPodTouch),
             @"iPod2,1": @(DeviceAppleiPodTouch2G),
             @"iPod3,1": @(DeviceAppleiPodTouch3G),
             @"iPod4,1": @(DeviceAppleiPodTouch4G),
             @"iPhone1,1": @(DeviceAppleiPhone),
             @"iPhone1,2": @(DeviceAppleiPhone3G),
             @"iPhone2,1": @(DeviceAppleiPhone3GS),
             @"iPhone3,1": @(DeviceAppleiPhone4),
             @"iPhone3,3": @(DeviceAppleiPhone4),
             @"iPhone4,1": @(DeviceAppleiPhone4S),
             @"iPhone5,1": @(DeviceAppleiPhone5),
             @"iPhone5,2": @(DeviceAppleiPhone5),
             @"iPhone5,3": @(DeviceAppleiPhone5C),
             @"iPhone5,4": @(DeviceAppleiPhone5C),
             @"iPhone6,1": @(DeviceAppleiPhone5S),
             @"iPhone6,2": @(DeviceAppleiPhone5S),
             @"iPhone7,1": @(DeviceAppleiPhone6_Plus),
             @"iPhone7,2": @(DeviceAppleiPhone6),
             @"iPhone8,1" :@(DeviceAppleiPhone6S),
             @"iPhone8,2" :@(DeviceAppleiPhone6S_Plus),
             @"iPhone8,4" :@(DeviceAppleiPhoneSE),
             @"iPhone9,1" :@(DeviceAppleiPhone7),
             @"iPhone9,3" :@(DeviceAppleiPhone7),
             @"iPhone9,2" :@(DeviceAppleiPhone7_Plus),
             @"iPhone9,4" :@(DeviceAppleiPhone7_Plus),
             @"iPad1,1": @(DeviceAppleiPad),
             @"iPad2,1": @(DeviceAppleiPad2),
             @"iPad3,1": @(DeviceAppleiPad3G),
             @"iPad3,4": @(DeviceAppleiPad4G),
             @"iPad2,5": @(DeviceAppleiPadMini),
             @"iPad4,1": @(DeviceAppleiPad5G_Air),
             @"iPad4,2": @(DeviceAppleiPad5G_Air),
             @"iPad4,4": @(DeviceAppleiPadMini2G),
             @"iPad4,5": @(DeviceAppleiPadMini2G),
             @"iPad4,7":@(DeviceAppleiPadMini),
             @"iPad6,7":@(DeviceAppleiPadPro12),
             @"iPad6,8":@(DeviceAppleiPadPro12),
             @"iPad6,3":@(DeviceAppleiPadPro9),
             @"iPad6,4":@(DeviceAppleiPadPro9)
             };
}

@end

以下是Aniruddh基于uname的方法的现代版本,它不依赖于Mirror,应该适用于Swift 4.2及更高版本:

import UIKit

extension UIDevice {
  var machineName: String {
    var info = utsname()
    return withUnsafeMutablePointer(to: &info) { info in
      // We could alternatively return nil here, or handle
      // errors some other way.
      guard uname(info) == 0 else { return model }
      let offset = MemoryLayout.offset(of: \utsname.machine)!
      let machine = UnsafeRawPointer(info).advanced(by: offset).assumingMemoryBound(to: CChar.self)
      return String(cString: machine)
    }
  }
}

虽然这个问题在2012年就被提出了,但苹果仍然没有给出将设备模式标识符转换为设备名称的方法。 有很多答案依赖于硬编码这些名称,不幸的是,当苹果发布新设备时,这些名称很快就过时了。

我们需要的是一种方法来获得一个不断更新的列表,它就在这里:https://github.com/ptrkstr/Devices

每次添加新设备时,这个Swift包都会更新,你所需要做的就是更新你的依赖项来获得它们。

Swift 4或更高版本

extension UIDevice {
    var modelName: String {
        if let modelName = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] { return modelName }
        var info = utsname()
        uname(&info)
        return String(String.UnicodeScalarView(
                   Mirror(reflecting: info.machine)
                    .children
                    .compactMap {
                        guard let value = $0.value as? Int8 else { return nil }
                        let unicode = UnicodeScalar(UInt8(value))
                        return unicode.isASCII ? unicode : nil
                    }))
    }
}

UIDevice.current.modelName   // "iPad6,4"

为了节省别人的时间。 因为接受,必须投票回答建议库使用私人API和我的应用程序被拒绝,因为uidevice-extension就在昨天! 我切换到GBDeviceInfo库,安装为pod以及,现在它看起来不错,维护和更新到最新的设备。