Tuesday, September 17, 2019

Breaking the NSData.description Contract

Mattt Thompson (tweet via Cédric Luthi):

iOS 13 changes the format of descriptions for Foundation objects, including NSData:

// iOS 12
(deviceToken as NSData).description // "<965b251c 6cb1926d e3cb366f dfb16ddd e6b9086a 8a3cac9e 5f857679 376eab7C>"

// iOS 13
(deviceToken as NSData).description // "{length = 32, bytes = 0x965b251c 6cb1926d e3cb366f dfb16ddd ... 5f857679 376eab7c }"

Whereas previously, you could coerce NSData to spill its entire contents by converting it into a String, it now reports its length and a truncated summary of its internal bytes.


Was Apple irresponsible in making this particular change?

No, not really — developers shouldn’t have relied on a specific format for an object’s description.

The documentation promises—still, as of this writing—that description returns:

A string that contains a hexadecimal representation of the data object’s contents in a property list format.

Perhaps it would be a mistake to rely on the exact format of the string, e.g. where the spaces are inserted. But, clearly, it is supposed to contain the entire data’s contents, in a format that can be reconstituted by the property list API. That is no longer the case, and the fault for any resulting breakage lies with Apple, not with developers who were relying on the API to do what it said it would do.

Apple hasn’t explained why it made the change, or even documented it in the release notes. In fact, there don’t even seem to be Foundation release notes yet.


Update (2019-09-17): Joe Groff:

It doesn’t break anything until you build with Xcode 11. The new behavior is based on the linked SDK version, so existing binaries keep working. If you want to upgrade your Xcode, you need to fix your code, though

Cédric Luthi:

Haha, I remember thinking “why did they introduce -UUIDString and not just used -description” for that purpose. Turns out, Apple thought about it too and changed the implementation of -[NSUUID description] in recent OS versions.

Seems like they should have provided a similar replacement on NSData for people relying on the old format.

Update (2019-09-18): Peter Steinberger:

Took the time to decompile [NSData description] on iOS 13 GMv2 and can verify that Apple did the sensible thing here: output only changes if linked SDK is > 12. Existing apps continue to work (forwards to debugDescription) once you adopt Xcode 11 they need to be fixed tho.

See also: this thread.

Update (2019-12-23): Sarah Edwards:

Anyone know how to make Xcode/plutil to stop truncating BLOBs? Seems to have started with macOS 10.15. Previously could see entire BLOB and export to hex editor, etc. Would prefer not to have to use 3rd party or conversion. This is driving me crazy.

This seems to be consequence of the change to NSData.

6 Comments RSS · Twitter

Why are people making comments about abuse of API or "fix your code" when this has been documented forever? ISTR someone (Andrew Stone or Bill Bumgarner?) pointing out that this was a design feature in some old Cocoa example code. Gratuitously breaking a decades-old documentation contract and then blaming developers is incredible.

[…] Another breaking change to an API that’s been around since Mac OS X 10.10, without updating the documentation or mentioning the change in a release note: […]

Is there a common fix for this? Im working on a codebase that uses this for getting Mac address in a lot of ares in the codebase and its going to take forever to fix this. Apple either should have left this alone or provided a solution.

@Michael To get the MAC address, see here.

This will work on iOS 13 with a Bee connected device ? I get a hex string like this
I already have the code the eliminate the
I will check it out !

edit: the hex value is closed with lesser and greater than symbols, and we have the code that removes those. We connect iOS to Ble devices and have to save the Mac address in core data..company decision, not mine.
I will check it out !

Leave a Comment