Reliable way to detect disk capacity of an iOS device

For one of my apps the disk capacity of the device it is running on is important to know, for example iPhone 6 (16GB) or iPhone 7 (128GB). The canonical way to query the disk capacity appears to be through `NSFileManager`. A function that returns the device capacity in GB as an `NSNumber` might look like this :


NSNumber * totalDiskSpaceInGb(void) {
  NSNumber *totalsize = [[NSFileManager.defaultManager attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize];
  return @(exp2(ilogb(totalsize.doubleValue) - 29));
}

This funtion served me well in the last couple of years but occasionally the value returned is off, in both directions, so I ended up detecting an 4 GB iPhone 5c, or a 512 GB iPhone 7.


The Settings.app displays the device capacity in General > About. Assuming that the algorithm is not the biggest secret at Apple, may I request how the Settings app calculates that value?

Replies

I don't know if this is something that you even have access to. The only thing you can check is NSHomeDirectory(). There is no guarantee that the filesystem of the home directory is the same as the rest of the device. On the Mac, for example, they are different.


You might be able to use IOKit to get the size of the underlying device. I have done this on a Mac, but not on iOS. Generally Apple doesn't want people (developers) knowing how much RAM or storage is available on the device.


Apple does support methods to manage storage, such as volumeAvailableCapacityForImportantUsageKey and volumeAvailableCapacityForOpportunisticUsageKey.

First up, a general point. You wrote:

The canonical way to query the disk capacity appears to be through

NSFileManager
.

No, that’s an old mechanism which I recommend that you avoid (as a rough guide, if the API uses file paths rather than file URLs, it’s old). The modern way to do this is the

volumeTotalCapacityKey
URL property.

Having said that, it won’t necessary help you here. You wrote:

For one of my apps the disk capacity of the device it is running on is important to know, for example iPhone 6 (16GB) or iPhone 7 (128GB).

I need to stress that this is a marketing value rather than a technical value. I’m not saying that this marketing value is not based on a technical value [1], but rather that its marketing nature affects people’s understanding of it. For example, a technical level getting a value of 15.99999 GB would be fine, but that’s not acceptable at a marketing level.

There is no good way to get this marketing value. So, regardless of what else you do, I recommend that you file an enhancement request for an API that returns this value explicitly (much like the

model
property of
UIDevice
returns the user-visible device model).

Please post your bug number, just for the record.

Beyond that, the problem you’re facing here is twofold. Firstly, iOS has no low-level APIs for interrogating the hardware. On macOS you could use I/O Kit to look at how the hardware fits together, but that API is not available on iOS.

Secondly, iOS devices have multiple volumes and the relationship between those volumes is not documented. On current systems there’s an immutable volume for the system and a writeable volume for apps, documents, and so on. However, these details are not documented and subject to change.

Indeed, this has changed in the past. Before the advent of APFS these volumes were represented by multiple partitions. Thus, to find the total size of the device you had to add up the sizes of each of these partitions. With the advent of APFS each of these volumes is carved out of a shared container. The traditional APIs for getting disk capacity can’t represent this subtlety, so each volume report’s the entire container’s size as its capacity. That’s why you’re getting back (roughly) the total disk size from

NSFileSystemSize
.

As to what you should do here, I don’t have a concrete answer. No matter what you do, it’s easy to imagine the system changing so that things fail in the future, and hence my earlier recommendation to file an ER. My only suggestion is that, after doing that, you open a DTS tech support incident requesting a workaround.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] See the fine print on our various Tech Spec pages.

> The modern way to do this is the

volumeTotalCapacityKey
URL property.


Just for completeness, the resulting values appear to be the same on 3 different devices I tested.


> I need to stress that this is a marketing value rather than a technical value.


My app is a disk benchmark, DiskBench. On SSDs, the performance strongly correlates with the capacity, so in this special case it is not purely marketing.


> There is no good way to get this marketing value.


Which means it is private API?


> I recommend that you file an enhancement request


Thanks, but I need to be as far backward compatible as possible.

>Which means it is private API?


Only if the thin air it's pulled out of is considered private. A marketing value is whatever you want it to be, after all. Throw a dart...it's up to you to round up/down, take an average, pull from an online advert, etc.