Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one get UI_USER_INTERFACE_IDIOM() to work with iPhone OS SDK < 3.2

Apple advises using the following code to detect whether running on an iPad or iPhone/iPod Touch:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
  // The device is an iPad running iPhone 3.2 or later.
  // [for example, load appropriate iPad nib file]
}
else {
  // The device is an iPhone or iPod touch.
  // [for example, load appropriate iPhone nib file]
}

The problem is that UI_USER_INTERFACE_IDIOM() and UIUserInterfaceIdiomPad are NOT defined in the SDKs prior to 3.2. This seems to completely defeat the purpose of such a function. They can only be compiled and run on iPhone OS 3.2 (iPhone OS 3.2 can only be run on iPad). So if you can use UI_USER_INTERFACE_IDIOM(), the result will always be to indicate an iPad.

If you include this code and target OS 3.1.3 (the most recent iPhone/iPod Touch OS) in order to test your iPhone-bound universal app code, you will get compiler errors since the symbols are not defined in 3.1.3 or earlier, when compiling for iPhone simulator 3.1.3.

If this is the recommended-by-Apple approach to runtime device-detection, what am I doing wrong? Has anyone succeeded using this approach to device-detection?

like image 307
drootang Avatar asked Apr 05 '10 00:04

drootang


4 Answers

I do this to get the code to compile in both 3.1.3 and 3.2:

BOOL iPad = NO;
#ifdef UI_USER_INTERFACE_IDIOM
iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#endif
if (iPad) {
// iPad specific code here
} else {
// iPhone/iPod specific code here
}

I also wrote a quick blog post about it here: http://www.programbles.com/2010/04/03/compiling-conditional-code-in-universal-iphone-ipad-applications/

like image 167
Sangraal Avatar answered Oct 22 '22 10:10

Sangraal


This is what I use:

- (BOOL) amIAnIPad {
    #if (__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200)
        if ([[UIDevice currentDevice] respondsToSelector: @selector(userInterfaceIdiom)])
            return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
    #endif
    return NO;
}

This conditionally compiles, so you can still build for the 3.0 sim. It then checks to see if the UIDevice class responds to the selector. If either of these fail, it's not an iPad.

like image 34
Ben Gottlieb Avatar answered Oct 22 '22 10:10

Ben Gottlieb


If this is the recommended-by-Apple approach to runtime device-detection, what am I doing wrong? Has anyone succeeded using this approach to device-detection?

This is solution for runtime detection:

#define isIPhone (![[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] || [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)

After that you can easily test it anywhere in your code:

if (isIPhone) { ... }

The difference between this and using #if / #ifdef is that this is runtime testing, while #if is compile-time testing.

I think the runtime testing is better, because you can use one exactable for any OS version in this case. If you use compile-time check, you'll need to produce different executables for different OS versions.

If your problem is compile-time errors, you just should compile against last version of SDK (see also How to access weak linked framework in iOS?).

like image 7
Mike Keskinov Avatar answered Oct 22 '22 08:10

Mike Keskinov


I believe the answer is simply do not attempt to run the code on iPhone simulator 3.1.3 or earlier. Always compile with a 3.2 SDK. The iPhone simulator 3.2 will get you the iPad simulator, or compile for iPhone Device 3.2 and put the app on a phone to test it.

There is no way to compile against 3.2 SDK and use a 3.1.3 or earlier simulator.

like image 5
drootang Avatar answered Oct 22 '22 09:10

drootang