8

I have written the following UIDevice category based on different sources. I've upgraded the platformCode method so it's less low-level than can be seen.

This works perfectly, but the platformCode method is low level. Do you know if this kind of call can be replaced with Cocoa Touch code? Here's the relevant code:

UIDevice_enhanced.h

@interface UIDevice (Enhanced)

typedef enum {
    kUnknownPlatform = 0,
    kiPhone1G,
    kiPhone3G,
    kiPhone3GS,
    kiPhone4,
    kiPhone4Verizon,
    kiPhone4S,
    kiPodTouch1G,
    kiPodTouch2G,
    kiPodTouch3G,
    kiPodTouch4G,
    kiPad,
    kiPad2Wifi,
    kiPad2GSM,
    kiPad2CMDA,
    kSimulator
} PlatformType;

- (NSString *) platformName;
- (PlatformType) platform;

@end

UIDevice_enhanced.m

#import "UIDevice_enhanced.h"
#include <sys/utsname.h>

@interface UIDevice (Enhanced)
- (NSString *) platformCode;
@end 


@implementation UIDevice (Enhanced)

// Utility method (private)
- (NSString*) platformCode {
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString* platform =  [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];

    return platform;
}

// Public method to use
- (NSString*) platformName {
    NSString* platform = [self platformCode];

    if ([platform isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";
    if ([platform isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";
    if ([platform isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";
    if ([platform isEqualToString:@"iPhone3,1"])    return @"iPhone 4";
    if ([platform isEqualToString:@"iPhone3,2"])    return @"Verizon iPhone 4";
    if ([platform isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
    if ([platform isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
    if ([platform isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
    if ([platform isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
    if ([platform isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
    if ([platform isEqualToString:@"iPad1,1"])      return @"iPad";
    if ([platform isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
    if ([platform isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
    if ([platform isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
    if ([platform isEqualToString:@"i386"])         return @"Simulator";

    return platform;
}

// Public method to use
- (PlatformType) platform {
    NSString *platform = [self platformCode];
    if ([platform isEqualToString:@"iPhone1,1"])    return kiPhone1G;
    if ([platform isEqualToString:@"iPhone1,2"])    return kiPhone3G;
    if ([platform isEqualToString:@"iPhone2,1"])    return kiPhone3GS;
    if ([platform isEqualToString:@"iPhone3,1"])    return kiPhone4;
    if ([platform isEqualToString:@"iPhone3,2"])    return kiPhone4Verizon;
    if ([platform isEqualToString:@"iPhone4,1"])    return kiPhone4S;
    if ([platform isEqualToString:@"iPod1,1"])      return kiPodTouch1G;
    if ([platform isEqualToString:@"iPod2,1"])      return kiPodTouch2G;
    if ([platform isEqualToString:@"iPod3,1"])      return kiPodTouch3G;
    if ([platform isEqualToString:@"iPod4,1"])      return kiPodTouch4G;
    if ([platform isEqualToString:@"iPad1,1"])      return kiPad;
    if ([platform isEqualToString:@"iPad2,1"])      return kiPad2Wifi;
    if ([platform isEqualToString:@"iPad2,2"])      return kiPad2GSM;
    if ([platform isEqualToString:@"iPad2,3"])      return kiPad2CMDA;
    if ([platform isEqualToString:@"i386"])         return kSimulator;

    return kUnknownPlatform;
}

@end
Oliver
  • 23,072
  • 33
  • 138
  • 230
  • This is perfectly valid Objective-C (as all C code), it's also not too low-level (I do recommend using enums rather than strings for finite multiple-choice sets). –  Dec 03 '12 at 08:32

2 Answers2

2

This may be considered an "objective-c" way of doing it:

// Utility method (private)
- (NSString *)platformCode {
    // This may or not be necessary 
    // Im not sure if you can have a device thats not currentDevice can you?
    // if ([self isEqual:[UIDevice currentDevice]]) {

    NSString* platform =  [[self.systemName copy] autorelease];
    return platform;

    // Could probably shorten to just
    // return [[self.systemName copy] autorelease];

    // or - return [NSString stringWithString:self.systemName];
}

This would be obj-c version of utsname machine (from this line: NSString* platform =  [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];).

utsname:

The <sys/utsname.h> header defines structure utsname, which includes at least the following members:

char sysname[]   name of this implementation of the operating system
char nodename[] name of this node within an implementation-dependent communications network
char release[]   current release level of this implementation
char version[]   current version level of this release
char machine[]   name of the hardware type on which the system is running

UIDevice Class Reference:

systemName The name of the operating system running on the device represented by the receiver. (read-only)
@property (nonatomic, readonly, retain) NSString *system


But, since systemName only returns @"iPhone OS", to get the actual device model number, you have to use c code. Here's another way to do it:

#include <sys/types.h>
#include <sys/sysctl.h>

- (NSString *)machine {
     size_t size;

    // Set 'oldp' parameter to NULL to get the size of the data
    // returned so we can allocate appropriate amount of space
    sysctlbyname("hw.machine", NULL, &size, NULL, 0); 

    // Allocate the space to store name
    char *name = malloc(size);

    // Get the platform name
    sysctlbyname("hw.machine", name, &size, NULL, 0);

    // Place name into a string
    NSString *machine = [NSString stringWithCString:name];

    // Done with this
    free(name);

    return machine;
}
chown
  • 51,908
  • 16
  • 134
  • 170
  • Yes, this is objective-C, but that does not allow to differentiate the devices... – Oliver Nov 06 '11 at 10:14
  • I thought you were asking how to convert the c code for the `platformCode` method to objective-c? Was there something else you were asking about? – chown Nov 06 '11 at 16:45
  • No, that was exactly what I was asking for, but your code does not return the same values than the C call, it's really less poor. In fact, as far as I have seen, it neither return anything that can be used to achieve the same goal than the C call. – Oliver Nov 06 '11 at 19:17
  • Ah, I think I understand what your asking. But the answer to that is that you have to use c. There is no objC way to get the model number. – chown Nov 06 '11 at 19:53
  • Updated link for UIDevice class reference: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDevice_Class/ – Spencer Williams Jun 24 '15 at 18:37
1

You'll have to use the low level C call to get the infoString. For my purposes I've written a tiny Objective-C library that abstracts this away and presents an Objective-C interface.

NSLog(@"Big model number: %d", deviceDetails.bigModel);
//Big model number: 4

NSLog(@"Small model number: %d", deviceDetails.smallModel);
//Small model number: 1

if (deviceDetails.model == GBDeviceModeliPhone4S) {
    NSLog(@"It's a 4S");
}
//It's a 4S

if (deviceDetails.family != GBDeviceFamilyiPad) {
    NSLog(@"It's not an iPad");
}
//It's not an iPad

NSLog(@"systemInfo string: %@", [GBDeviceInfo rawSystemInfoString]);
//systemInfo string: iPhone4,1

You can get it on github if you like: GBDeviceInfo

lmirosevic
  • 15,787
  • 13
  • 70
  • 116