NSURL changes for OS X 10.9 and iOS 7 that might break your code

I originally thought I might do some sort of super-short presentation on this subject, but since no opportunity has arisen yet, a blog post it is instead then!

File paths

Cocoa has had convenience methods for creating URLs from file paths (+fileURLWithPath: etc.) since pretty much forever now. OS X 10.9 and iOS 7 have changed the form of URLs created through these methods:

  • Before: /foo/bar => file://localhost/foo/bar
  • Now: /foo/bar => file:///foo/bar

Cocoa’s various URL-based facilities have always supported both forms, so you should have no problems there. This change results in slightly lower memory usage (as no memory is wasted storing the redundant localhost string). But I reckon there’s a few gotchas it’s possible your code could hit with this, particularly if there’s a chance of the older style URLs being brought in to your app via some sort of persistence mechanism.

-host now returns nil rather than @"localhost", so make sure any comparisons account for that. Indeed, be a little wary of any code you have that tries to test equality of entire URLs or strings. In the case of file URLs, I reckon you’re better off comparing -path, or perhaps NSURLFileResourceIdentifierKey.

Update: Well look at that, turns out I’ve been bitten by this change without realising till now; my routine for deriving relative URL strings was being too conservative when handed a file:/// URL.

If you were relying on -resourceSpecifier to extract everything but the scheme (quite an edge case I know, but we were messing around with this in Sandvox), that will now give you the unexpected result in the example above of /foo/bar, rather than ///foo/bar.

Invalid characters

Apple’s release notes have this to say:

URL objects created from URL strings where the URL string length was exactly 1 can no longer be created with characters not allowed in URL strings. This change affects CFURL's CFURLCreateWithString(), and the NSURL methods -initWithString:, -initWithString:relativeToURL:, +URLWithString:, and +URLWithString:relativeToURL:.

However in my testing (thanks to Stack Overflow), the bug (I’m guessing it’s the same bug, but could be wrong) seems a bit broader. On OS X 10.8 and earlier, it appears that NSURL will cheerfully accept anything as the last character of the URL. Furthermore, it even goes to the trouble of percent encoding that character! So take this for example:

Note the space character at the end of the URL. This is invalid, so should result in url being nil. Instead though, prior to OS X 10.9 / iOS 7, it results in http://example.com/path%20.

Try adding a space anywhere else in that example string and you’ll consistently get nil. Seems to be a quirk specific to the last character.

The practical upshot is it’s possible you’ve got some code which just happened to work before (since it was only ever tested with a single, trailing invalid character) and now behaves differently.

© Mike Abdullah 2007-2015