Cocoa: Please never draw your NSView, NSCell and CALayer using -[NSScreen backingScaleFactor]
This is so wrong! And I saw it in many StackOverflow answers.
I have a Retina Mac which is almost always plugged to an external non-retina 22” monitor: some windows are drawn as retina and some are not. And it matters. The shortcut I’ve seen too often is [[NSScreen mainScreen] backingScaleFactor]. My main screen is the built-in retina one so this call will always return 2.0f ; then what about the windows on the external non-retina display? They will be drawn for a retina display, and then uglily scaled down by the system.
Why people are getting confused with NSScreen?
This back practice is probably inherited from iOS, where everyone’s dealing with the UIScreen. Well, this is wrong on iOS too, since an iOS device can have multiple screens and windows. Think about AirPlay.
The right answer
It's so simple. If you are drawing in your NSView or NSCell code, just call -[[myView window] backingScaleFactor]. In the case the window is moved across screens, all will be redrawn with the new backing scale factor. Though, it’s a little trickier if you’re using a CALayer. In your -[CALayer drawInContext:] method, get [self contentSize]. This part is easy, but the view backed by the CALayer needs to keep the layer updated by any change of the scale factor:
- (void)viewDidChangeBackingProperties { [super viewDidChangeBackingProperties]; [[self layer] setContentsScale:[[self window] backingScaleFactor]]; }
Hope it helps! And please give me a favor, forget about -[NSScreen backingScaleFactor].











