6

I am attempting to detect whether the current device is iPhone5, iPhone6 or iPhone 6 Plus.

In my app I am already using this macro to detect iPhone 5 which works perfectly.

#define IS_IPHONE_5      (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)568) < DBL_EPSILON)

Similarly, I use this macro to detect iPhone 6 and iPhone 6 Plus.

#define IS_IPHONE_6      (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)667) < DBL_EPSILON)
#define IS_IPHONE_6_PLUS (fabs((double)[[UIScreen mainScreen]bounds].size.height - (double)736) < DBL_EPSILON)

The IS_IPHONE_5 macro works as expected in any orientation.

My problem is that the IS_IPHONE_6 and IS_IPHONE_6_PLUS macros do not return true when the device is held in LANDSCAPE. However they do work as expect while the device is held in PORTRAIT. What gives?

Also if anyone has a better recommendation to detect iPhone5, 6 and 6 Plus please share.

leejona
  • 115
  • 1
  • 4
  • 3
    Why do you think you need macros like these? What are you using them for? – rmaddy Oct 01 '14 at 18:36
  • 4
    Under iOS 8, none of your macros work when the app is launched in landscape because under iOS 8, the screen's size actually reflects the app's orientation. In iOS 7 and earlier, the screen size never reflected the actual device orientation. – rmaddy Oct 01 '14 at 18:37
  • Are you using the macro after the device orientation transition is over? Which device orientations are supported by your target? – psobko Oct 01 '14 at 18:47
  • @rmaddy I need these because my app contains a custom table view when rotated to landscape. This table view is formatted to display column headers and rows accordingly based on complex managed object modals. On the iPhone 4 there was only so much screen estate to display x amount of columns. When the iPhone 5 came out, I took advantage of the screen size so that I could display more columns which would provide additional information that could just not fit on the iPhone 4. Now I am looking to take advantage of the iPhone 6 screen size to display even more information for a more complete table. – leejona Oct 01 '14 at 18:50
  • 2
    OK. That's good. But why hardcode logic based on the device? Why not simply look at the current view size and display what fits? Then your app works on all devices and orientations without needing crazy, device and orientation specific logic. – rmaddy Oct 01 '14 at 18:53
  • @rmaddy Yes you are correct in your second comment. I have noticed that under iOS8 the screen size reflects the actual device orientation. I was wondering if there was a work around to this or if I should use a different approach. – leejona Oct 01 '14 at 18:55
  • Yes, use a different approach - the one I mentioned in my previous comment. Base all decisions off of the view's width, not any specific device or orientation. – rmaddy Oct 01 '14 at 18:57
  • @rmaddy The reason behind that is because these columns are not fixed length. I basically have a dictionary of width values. For example, column 1 and 2 contain fields that hold longer string values, so I need the columns to be wider in order to accommodate, while columns 3+ contain shorter strings. The goal is basically to fit more content comfortably based on screen size available. – leejona Oct 01 '14 at 19:07
  • @rmaddy I've decided it was a better idea to go with your approach based on screen size. In this app I was already using the IS_IPHONE_5 macro and figured it would be simple and quick to just throw in an IS_IPHONE_6 / IS_IPHONE_6_PLUS macro rather then checking for screen size. – leejona Oct 01 '14 at 19:29
  • What on earth is the DBL_EPSILON for? Are you afraid that Apple will make an iPhone with 736.000000000001 pixels? – gnasher729 Oct 02 '14 at 09:00

4 Answers4

8

This is tested and designed for any combination of iOS system versions and SDK versions

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
#define IS_RETINA ([[UIScreen mainScreen] scale] >= 2.0)

#define SCREEN_WIDTH ([[UIScreen mainScreen] bounds].size.width)
#define SCREEN_HEIGHT ([[UIScreen mainScreen] bounds].size.height)
#define SCREEN_MAX_LENGTH (MAX(SCREEN_WIDTH, SCREEN_HEIGHT))
#define SCREEN_MIN_LENGTH (MIN(SCREEN_WIDTH, SCREEN_HEIGHT))

#define IS_IPHONE_4_OR_LESS (IS_IPHONE && SCREEN_MAX_LENGTH < 568.0)
#define IS_IPHONE_5 (IS_IPHONE && SCREEN_MAX_LENGTH == 568.0)
#define IS_IPHONE_6 (IS_IPHONE && SCREEN_MAX_LENGTH == 667.0)
#define IS_IPHONE_6P (IS_IPHONE && SCREEN_MAX_LENGTH == 736.0)

Note: If iPhone 6 is in zoomed mode the UI is a zoomed up version of iPhone 5. This is reflected in the macros.

Usage: http://pastie.org/9687735

hfossli
  • 22,616
  • 10
  • 116
  • 130
3

Don't use the screen size for this, it's better to use the hardware model. We are getting more and more screen sizes every year, the less you hard-code screen dimensions in your code the better for your future self.

You need a helper function to get the machine name. I'm using dispatch_once to avoid querying the system multiple times for data that won't change.

NSString* machineName()
{
    static NSString* name = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        struct utsname systemInfo;
        uname(&systemInfo);
        name = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    });
    return name;
}

Then define a few macros as needed:

#define IS_IPHONE_6      [machineName() isEqualToString:@"iPhone7,2"]
#define IS_IPHONE_6_PLUS [machineName() isEqualToString:@"iPhone7,1"]

For some models is trickier:

#define IS_IPHONE_5s     [machineName() hasPrefix:@"iPhone6,"]

Finally, use the macros in your code:

if (IS_IPHONE_6) {
// for the 6
}

Note: This answer your question (detect models with macros) but you're doing it wrong IMHO. You should use autolayout and size classes, unless you support really old iOS versions...

djromero
  • 19,551
  • 4
  • 71
  • 68
1

Take a look at this answer: iOS - How to get device make and model? it doesn't use macros but it does the job. I've seen some similar problems with macros to detect iPhone 6 and iPhone 6 plus. So it would be a better idea to try out the answer from @Ohhmee

EDIT: Of course there probably is a solution detecting it with macros. But I don't know that and I can't find a solution so i'm suggesting a different approach.

Community
  • 1
  • 1
Bas
  • 4,423
  • 8
  • 36
  • 53
  • 2
    This doesn't answer the question and checking device models is rarely an appropriate solution. – rmaddy Oct 01 '14 at 18:39
  • It does answer the question, because he states: 'Also if anyone has a better recommendation to detect iPhone5, 6 and 6 Plus please share. – Bas Oct 01 '14 at 18:40
  • 1
    Oops. I guess I didn't read that last line. OK. But the latter part of my comment still stands (more to the OP than the answerer). Few people using these macros or using device model strings are doing so with a valid reason. Such code is just going to break again when Apple comes out with devices with different sizes again. – rmaddy Oct 01 '14 at 18:44
0

Your macros are ridiculous and seem to indicate a fear of floating-point arithmetic.

#define IS_IPHONE_5      ([UIScreen mainScreen].bounds.size.height == 568)
#define IS_IPHONE_6      ([UIScreen mainScreen].bounds.size.height == 667)
#define IS_IPHONE_6_PLUS ([UIScreen mainScreen].bounds.size.height == 736)

will work just as good (or just as bad). Most likely they will work just as bad.

If you are interested in features of the iPhone 6 or 6+, check for the features, not the screen size. It is quite likely that Apple will soon have a 4" phone with all the iPhone 6 features. Or a cheap 6c with a big screen but without iPhone 6 features.

For user interface and so on, just take the mainScreen bounds and lay out your views accordingly. At this point, hard coding for fixed sizes is absolutely ridiculous and will bite you. You should be able to run for example on a 12" iPad with a split screen without problems, and heavens knows what screen size that will be.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • Downvote because `==` comparsion with floating point is indeed a bad idea in general, there is even a compiler warning for that which you can enable (`-Wfloat-equal`, [read description here](http://klurl.nl/?u=jX0D41)). E.g. `a = 0.15 + 0.15` and `b = 0.1 + 0.2`, both are 0.30, yet `a == b` is __NOT__ guaranteed to be true by floating point standards. This has nothing to do with _a fear of floating-point arithmetic_, your answer rather indicates _a lack of knowledge about floating-point arithmetic_. Also watch your wording, calling them _ridiculous_ is not the right tone on SO. – Mecki Dec 09 '14 at 15:57