Undocumented NSShadow Change on Catalina
Curiously, the API documentation for shadowOffset is now shared between AppKit and UIKit.
[…]
So there is a change in behavior of NSShadow shadowOffset in AppKit on Catalina, presumably to emulate UIKit. Sigh… why does the Mac always have to emulate iOS now? Unfortunately, AppKit developers were not informed of the change, because there were no AppKit release notes published for Catalina.
If you want the shadowOffset to behave as (you) intended on all versions of macOS, both before and after Catalina, the workaround is to check
if (@available(macOS 10.15, *))
and switch the sign of your offset height accordingly.
Also your article surfaces for me that the number of mandatory @available checks to workaround bugs and API changes is really getting bad for my app.
@hypeapp runs on macOS 10.10+ and has 111 checks! These are for compatibility and not to make use of new OS features.
Also, some enum values have changed on Apple Silicon Macs:
The
NSTextAlignment
enumeration uses different numerical values for some constants onarm64
andx86_64
architectures. When referring to constants using numerical values, validate that you use the correct values on each architecture.The
NSImageResizingMode
andUIImageResizingMode
enumerations uses different numerical values for some constants onarm64
andx86_64
architectures. When referring to constants using numerical values, validate that you use the correct values on each architecture.
See TARGET_ABI_USES_IOS_VALUES
in the headers. I’m not sure how this interacts with archiving.
7 Comments RSS · Twitter
Seems to be limited to NSAttributedString drawing, not NSShadow in general. My app versions compiled with Xcode 10 and 12 draw it as expected on macOS 10.14 and 10.15.
NSTextAlignment's documentation says what the numeric values are. That's part of the public interface. Is Apple documentation saying that Apple documentation is wrong?
The change in NSTextAlignment bit my app since I had the values assigned as control/menu tags in certain XIB files. A generic action like -changeAlignment: would inspect the sender's tag to apply the desired alignment, which is now wrong on ARM.
I understand Apple's motivation here. Unifying these values to be the same on both platforms makes sense. I only wonder why UIKit didn't use the AppKit values from the very beginning?
I filed a documentation bug request with Apple about this discrepancy and recently got an answer:
Please note that we plan to update the header as the docs are correct.
Shadows when drawn through NSGraphicsContext and CGContext operate in their own coordinate systems. This allows them to project *down* and to the right, regardless of whether the coordinate system is flipped. Shadows are not always drawn this way, though. One common way that happens is by mapping an NSShadow to a CALayer’s shadow properties. CALayer and its shadow share a coordinate system, so the offset doesn’t always mean the same thing.
Got an update from Apple that they have update https://developer.apple.com/documentation/uikit/nsshadow, https://developer.apple.com/documentation/uikit/nsshadow/1429851-shadowoffset and https://developer.apple.com/documentation/uikit/nsshadow/1429846-shadowblurradius to reflect how shadows are rendered.
I see in Xcode 13.1 that the constants for NSTextAlignment have a Note saying that they have different values under certain conditions:
Declaration
NSTextAlignmentRight = 2
Discussion
Note
In Mac apps, including apps built with Mac Catalyst, the value of this enumeration case is 1.
The note seems incorrect, though: To me it suggests that the value is 1 in ALL Mac apps, but it's only the case for Intel arch, not for ARM arch.