224
votes

Does iOS SDK provides an easy way to check if the currentDevice has an high-resolution display (retina) ?

The best way I've found to do it now is :

    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
         // RETINA DISPLAY
    }
14
Out of curiosity - what are you doing when you detect the display other than showing larger versions of your art work?Michael Behan
@mbehan: I have a TTImageView (see Three20 framework) and I want to give an high-resolution url of the image.Pierre Valade
This question is also useful to me because I have downloaded images that present as UI available in sizes for all 4 display sizes & only want to have users download the appropriate one.Pedro
@mbehan: in my case I wanted custom cell separators that are 1px on both retina & non-retina screens (like the native separators). Setting the thickness to 1px renders at 2px on retina displays (obviously).user3099609

14 Answers

295
votes

In order to detect the Retina display reliably on all iOS devices, you need to check if the device is running iOS4+ and if the [UIScreen mainScreen].scale property is equal to 2.0. You CANNOT assume a device is running iOS4+ if the scale property exists, as the iPad 3.2 also contains this property.

On an iPad running iOS3.2, scale will return 1.0 in 1x mode, and 2.0 in 2x mode -- even though we know that device does not contain a Retina display. Apple changed this behavior in iOS4.2 for the iPad: it returns 1.0 in both 1x and 2x modes. You can test this yourself in the simulator.

I test for the -displayLinkWithTarget:selector: method on the main screen which exists in iOS4.x but not iOS3.2, and then check the screen's scale:

if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
    ([UIScreen mainScreen].scale == 2.0)) {
  // Retina display
} else {
  // non-Retina display
}
81
votes

@sickp's answer is correct. Just to make things easier, add this line into your Shared.pch file:

#define IS_RETINA ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale >= 2.0))

Then in any file you can just do:

if(IS_RETINA)
{
   // etc..
}
20
votes
+(BOOL)iPhoneRetina{
    return ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && ([UIScreen mainScreen].scale == 2.0))?1:0;
}
10
votes

Here is a handy swift extension:

Update for Swift v5:

extension UIScreen {

    public var isRetina: Bool {
        guard let scale = screenScale else {
            return false
        }
        return scale >= 2.0
    }

    public var isRetinaHD: Bool {
        guard let scale = screenScale else {
            return false
        }
        return scale >= 3.0
    }

    private var screenScale: CGFloat? {
        guard UIScreen.main.responds(to: #selector(getter: scale)) else {
            return nil
        }
        return UIScreen.main.scale
    }
}

Usage:

if UIScreen.main.isRetina {
    // Your code
}

Original:

extension UIScreen { 
public func isRetina() -> Bool {
    return screenScale() >= 2.0
}

public func isRetinaHD() -> Bool {
    return screenScale() >= 3.0
}

private func screenScale() -> CGFloat? {
    if UIScreen.mainScreen().respondsToSelector(Selector("scale")) {
        return UIScreen.mainScreen().scale
    }
    return nil
    }
}

Usage:

if UIScreen.mainScreen().isRetina() {
 // your code
        }
6
votes

This snippet...

    int d = 0; // standard display
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0) {
    d = 1; // is retina display
}

if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
    d += 2;
}

Will return... 0 for standard resolution iPhone/iPod touch, 1 for retina iPhone, 2 for standard resolution iPad, 3 for retina iPad.

6
votes

SSToolkit has a method that does this:

http://sstoolk.it/documentation/Categories/UIScreen(SSToolkitAdditions).html

It is used in the following way:

[[UIScreen mainScreen] isRetinaDisplay];
6
votes

It always feels a bit dodgy to compare floating-point values for equality. I prefer going for either

[UIScreen mainScreen].scale > 1.0;

or

[UIScreen mainScreen].scale < 2.0;
2
votes

This is a riff on Matt MC's answer above. Just a category on UIScreen.

#import "UIScreen+Util.h"

@implementation UIScreen (Util)

+ (BOOL) isRetinaDisplay {
    static BOOL retina = NO;
    static BOOL alreadyChecked = NO;
    if (!alreadyChecked) {
        UIScreen *mainScreen = self.mainScreen;
        if (mainScreen) {
            retina = mainScreen.scale > 1.0;
            alreadyChecked = YES;
        }
    }
    return retina;
}

@end
2
votes

Swift version of the answers above, with >= 2.0 scale so it includes iPhone 6+ and other future devices with higher-than-Retina scale:

 if UIScreen.mainScreen().respondsToSelector(Selector("scale")) && UIScreen.mainScreen().scale >= 2.0 {
    // code executed only on Retina device
}
1
votes

Just to combine the answer from @sickp and the following comment from @n13 I made this into a UIScreen category which seems to work nicely. The check is done the first time you call it and then saved for later calls.

@interface UIScreen (RetinaCheck)
+ (BOOL)retinaScreen;
@end

static BOOL isRetinaScreen = NO;
static BOOL didRetinaCheck = NO;

@implementation UIScreen (RetinaCheck)
+ (BOOL)retinaScreen
{
    if (!didRetinaCheck) {
        isRetinaScreen = ([[self mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
                          ([self mainScreen].scale == 2.0));
        didRetinaCheck = YES;
    }
    return isRetinaScreen;
}
@end

Might be useful to someone.

1
votes
// .h
UIKIT_EXTERN bool isRetinaDisplay();

// .m
bool isRetinaDisplay()
{
    static bool flag;
#ifdef __BLOCKS__
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        {
            flag = [[UIScreen mainScreen] scale] > 1.0;
        }
        else
        {
            flag = false;
        }
    });
#else
    static bool onceToken;
    if(onceToken == false)
    {
        onceToken = true;
        if([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
        {
            flag = [[UIScreen mainScreen] scale] > 1.0;
        }
        else
        {
            flag = false;
        }
    }
#endif
    return flag;
}
0
votes

try this

if ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] &&
    ([UIScreen mainScreen].scale == 2.0))
{
    // Retina display
    NSLog(@"---------------Retina display");
} else {
    // non-Retina display
    NSLog(@"---------------non-Retina display");
}
0
votes

Modified version of primulaveris's for simplicity of most common use cases. I'm on swift 2.2 but it shouldn't matter.

extension UIScreen {
    static var isRetina: Bool {
        return screenScale >= 2.0
    }

    static var isRetinaHD: Bool {
        return screenScale >= 3.0
    }

    static var screenScale:CGFloat {
        return UIScreen.mainScreen().scale
    }
}

Then simply use them like this

print(UIScreen.isRetina)
print(UIScreen.isRetinaHD)
print(UIScreen.screenScale)
0
votes

This worked for me

if((UIScreen .mainScreen().scale) < 2.0)
{
    NSLog("no retina");
}
else
{
    NSLog("retina");
}