Get Folder's Number of Elements

IMPORTANT I want to stress that I wasn’t involved in making these decisions, I have just watched them go by over the years.

I also wish there was clearer documentation about why Foundation/Apple
went this route.

I don’t think we ever documented this officially, but to understand this choice you have to look at the history of macOS. Traditional Mac OS did not use paths a lot. Rather, files were identified by an FSSpec [1] [2], which contains a volume identifier, a directory ID, and a name. The directory ID was an HFS [Plus] catalogue node ID (CNID), which is kinda like an inode number [3].

Additionally, starting with System 7 it was possible to track a file with a volume identifier and the file ID, that is, the CNID of the file itself.

This was quite tricky to support on a Unix-y platform like Mac OS X. At the lowest levels of the system you needed the ability to manipulate files based on CNIDs rather than paths. For an explanation of how this was done, see QA1113 The "/.vol" directory and "volfs" (note, however, that volfs is no longer a thing and the same functionality is now implemented in a very different way).

Moreover, this ability to work with files based on their CNID was important for Foundation as well. We solved this problem with file reference URLs. These used [4] a different URL scheme, one that encoded the traditional FSSpec values in the URL path. This is why we have routines like -[NSURL isFileURL], which returned true for URLs with both the standard file URL scheme and the custom one used by file reference URLs [5], and -fileReferenceURL, which creates a file reference URL from a standard URL.

So far, so much obscure backward compatibility. However, since we made the decision to use file URLs we’ve exploited that to significant advantage:

  • File URLs can cache property values. This is really useful for things like -[NSFileManager contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:], which returns an easy-to-use array of URLs that’s also performant because those URLs cache the attributes that you request via the includingPropertiesForKeys parameter. It’s a bit shocking that, in most practical scenarios, this NSURL API is faster than the lower-level readdir API. To beat it you have to call getdirentriesattr directly (see its man page).

  • File URLs can hold extra metadata. A critical use case here is the security scope used by the App Sandbox on macOS and the general sandbox on iOS and its descendents.

Moreover, my experience is that file paths have all sorts of gotchas that folks tend to ignore because they’re either obscure (like normalisation) or well-known (like getting the separators right). If you give someone a file path they’ll inevitably start manipulating it as a string, and at some point that’ll end badly.

Honestly, I’m not a big fan of file names — in the sense that I consider the name of a file to be just one item of metadata that’s not fundamentally different from, say, its creation date — but that’s an argument for another day (-:

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

[1] Technically an FSSpec is a System 7 thing, but systems prior to that used the same info just not packed into a handy structure.

[2] Late in traditional Mac OS’s life (Mac OS 9?) we introduced a new File Manager API based on FSRef values. You can think of these as an opaque form of FSSpec, so I’m going to focus on FSSpec here. However, the way that these FSRef values worked made it even more important that Mac OS X was able to represent them with high fidelity.

[3] There are important semantic differences here but if you come from a Unix background this is the closest approximation.

[4] Again, this has changed since it was originally introduced.

[5] To be clear, this custom scheme is no longer in use and file reference URLs now use the standard file scheme with a path that encode the necessary info.

53 Likes