32

Is there an API for checking at runtime whether you are running on an iPhone or an iPad?

One way I can think of would be to use:

[[UIDevice currentDevice] model];

And detect the existence of the string @"iPad" - which seems a bit fragile.

In the 3.2 SDK, I see that UIDevice also has a property which is really what I'm looking for, but doesn't work for pre-3.2 (obviously):

[[UIDevice currentDevice] userInterfaceIdiom]; 

Are there other ways than checking for the existence of @"iPad" for a universal app?

Eric
  • 3,865
  • 4
  • 32
  • 44

5 Answers5

41

Checkout UI_USER_INTERFACE_IDIOM.

Returns the interface idiom supported by the current device.

Return Value
UIUserInterfaceIdiomPhone if the device is an iPhone or iPod touch or UIUserInterfaceIdiomPad if the device is an iPad.

UIUserInterfaceIdiom

The type of interface that should be used on the current device

typedef enum {
   UIUserInterfaceIdiomPhone,
   UIUserInterfaceIdiomPad,
} UIUserInterfaceIdiom;
Community
  • 1
  • 1
Andiih
  • 12,285
  • 10
  • 57
  • 88
  • Gotcha - I can use respondsToSelector:@selector(userInterfaceIdiom) instead of checking for the existence of the string "iPad". Thanks! – Eric May 21 '10 at 18:43
  • 7
    use the macro - later OS's will respond to the selector, but not necessarily be an iPad. – Andiih May 21 '10 at 18:50
  • 1
    Ok, I'm learning. :) My #fail: I've been using the simulator to toggle between iPhone and iPad by switching the Active SDK between 3.2 and 3.1 - in which it no longer compiled when the Active SDK is 3.1. Then I jolted the neurons with some caffeine and plugged the #ifdef UI_USER_INTERFACE_IDIOM around it... Anyway, thanks for the followup Andiih - and if I've just compounded my #fail to something #worsethanfailure with the #ifdef, let me know. :) – Eric May 21 '10 at 21:08
  • 1
    Just for cross-linking's sake: http://stackoverflow.com/questions/2576356/how-does-one-get-ui-user-interface-idiom-to-work-with-iphone-os-sdk-3-2 – Dan Rosenstark Aug 16 '10 at 05:32
  • 5
    One caveat: If the iPad user is running an iPhone-only app (as in non-universal) the UI_USER_INTERFACE_IDIOM function will report the device as an iPhone. – Jason Fuerstenberg Jul 21 '12 at 07:08
  • @Andiih Would be better to include some source instead of a link. – bugfixr Feb 17 '14 at 12:38
15

Just for my reference:

@property (nonatomic, readonly) BOOL isPhone;

-(BOOL)isPhone {
    return (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone);
}

or use a #define

#define IS_PHONE  (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)

However, if you're using isPhone all over your code, that's generally bad practice. Use the factory pattern and polymorphism to keep your if statements contained, so you get objects created for phone or for iPad and then work with those.

Added

I'm using this solution all over my code now. It adds a standard factory pattern into the alloc.

#define ALLOC_PER_DEVICE()  id retVal = nil; \
                        NSString *className = NSStringFromClass(self);\
                        if (IS_PHONE && ![className hasSuffix:@"Phone"]) {\
                            className = [NSString stringWithFormat:@"%@Phone", className];\
                            Class newClass = NSClassFromString(className);\
                            retVal = [newClass alloc];\
                        }\
                        if (!retVal)\
                            retVal = [super alloc];\
                        assert(retVal != nil);\
                        return retVal\

Then my allocs look like this:

+alloc { ALLOC_PER_DEVICE(); }

And I add a subclass called TheClassPhone for the phone version.

Note: Since there's no multiple inheritance in Objective-C, using inheritance to solve your problems is a bit overrated (i.e., it doesn't work if you have subclasses of subclasses). Nothing like a good if when you need it.

Martin
  • 10,738
  • 14
  • 59
  • 67
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • Hi, learner of Objective-C here. Just wondering why it's not necessarily a good idea to say make a utilities class and then add an "isPhone" static method to it so that I can do if([utilities isPhone]) { /* iphone stuff */ }else{ /* ipad stuff */ } throughout my project? Also, why do you define your method as a property? – David Zorychta May 17 '13 at 00:41
  • utilities class with class methods is fine. I define it as a property because I want to use it that way. – Dan Rosenstark May 19 '13 at 15:52
  • If your `Utilities` class is a singleton, then you can use `utilities isPhone` otherwise make class methods. Singleton is definitely the recommended way to go. Methods as properties are the same. Objective-C is flexible like that. – Dan Rosenstark May 19 '13 at 19:59
1

You can check if you run the app on iPhone or iPad by using the following code:

- (NSString *)deviceModel
{
    struct utsname systemInfo;
    uname(&systemInfo);
    return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}

- (NSString *) platformString
{
    NSString *platform = [self deviceModel];
    if ([platform isEqualToString:@"iPhone1,1"])    return @"iPhone_2G";
    else if ([platform isEqualToString:@"iPhone1,2"])    return @"iPhone_3G";
    else if ([platform isEqualToString:@"iPhone2,1"])    return @"iPhone_3GS";
    else if ([platform isEqualToString:@"iPhone3,1"])    return @"iPhone_4";
    else if ([platform isEqualToString:@"iPhone3,3"])    return @"Verizon_iPhone_4";
    else if ([platform isEqualToString:@"iPhone4,1"])    return @"iPhone_4S";
    else if ([platform isEqualToString:@"iPhone5,1"])    return @"iPhone_5";
    else if ([platform isEqualToString:@"iPhone5,2"])    return @"iPhone_5";
    else if ([platform isEqualToString:@"iPod1,1"])      return @"iPod_Touch 1G";
    else if ([platform isEqualToString:@"iPod2,1"])      return @"iPod_Touch 2G";
    else if ([platform isEqualToString:@"iPod3,1"])      return @"iPod_Touch 3G";
    else if ([platform isEqualToString:@"iPod4,1"])      return @"iPod_Touch 4G";
    else if ([platform isEqualToString:@"iPad1,1"])           return @"iPad_1G";
    else if ([platform isEqualToString:@"iPad2,1"])      return @"iPad_2(WiFi)";
    else if ([platform isEqualToString:@"iPad2,2"])      return @"iPad_2(GSM)";
    else if ([platform isEqualToString:@"iPad2,3"])      return @"iPad_2(CDMA)";
    else if ([platform isEqualToString:@"iPad3,1"])      return @"iPad_3";
    else if ([platform isEqualToString:@"iPad3,2"])      return @"iPad_3(GSM/CDMA)";
    else if ([platform isEqualToString:@"iPad3,3"])      return @"iPad_3(GSM)";
    else if ([platform isEqualToString:@"iPad3,4"])      return @"iPad_3(GSM)";
    else if ([platform isEqualToString:@"iPad2,5"])      return @"iPad_mini_1G";
    else if ([platform isEqualToString:@"i386"])         return @"Simulator";
    else if ([platform isEqualToString:@"x86_64"])       return @"Simulator";
    return platform;
}
Ahmed Hammad
  • 435
  • 4
  • 8
1

Use NSClassFromString and an iPad-specific class. Read more here:

http://developer.apple.com/iphone/library/documentation/General/Conceptual/iPadProgrammingGuide/StartingYourProject/StartingYourProject.html#//apple_ref/doc/uid/TP40009370-CH9-SW3

Jeff Kelley
  • 19,021
  • 6
  • 70
  • 80
1
  1. Check for the presence of the userInterfaceIdiom property, usings respondsToSelector:. If it doesn't exist, we are on a pre-3.2 device, thus not an iPad.
  2. If userInterfaceIdiom exists, use it.

Edit: ... which is obviously exactly what the UI_USER_INTERFACE_IDIOM() macro does, so use that instead. :)

Jakob Borg
  • 23,685
  • 6
  • 47
  • 47