How to detect total available/free disk space on the iPhone/iPad device?

89,750

Solution 1

UPDATE: Since a lot of time has passed after this answer and new methods/APIs have been added, please check the updated answers below for Swift etc; Since I've not used them myself, I can't vouch for them.

Original answer: I found the following solution working for me:

-(uint64_t)getFreeDiskspace {
    uint64_t totalSpace = 0;
    uint64_t totalFreeSpace = 0;
    NSError *error = nil;  
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];  

    if (dictionary) {  
        NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize];  
        NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
        totalSpace = [fileSystemSizeInBytes unsignedLongLongValue];
        totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
        NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll));
    } else {  
        NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %ld", [error domain], (long)[error code]);
    }  

    return totalFreeSpace;
}

It returns me exactly the size that iTunes displays when device is connected to machine.

Solution 2

Revised source using unsigned long long:

- (uint64_t)freeDiskspace
{
    uint64_t totalSpace = 0;
    uint64_t totalFreeSpace = 0;

    __autoreleasing NSError *error = nil;  
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];  

    if (dictionary) {  
        NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize];  
        NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize];
        totalSpace = [fileSystemSizeInBytes unsignedLongLongValue];
        totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
        NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll));
    } else {  
        NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %d", [error domain], [error code]);  
    }  

    return totalFreeSpace;
}

EDIT: it seems someone edited this code to use 'uint64_t' instead of 'unsigned long long'. While in the foreseeable future this should be just fine, they are not the same. 'uint64_t' is 64 bits and will always be that. In 10 years 'unsigned long long' might be 128. its a small point but why I used unsignedLongLong.

Solution 3

I have written a class to get available/used memory using Swift. Demo at: https://github.com/thanhcuong1990/swift-disk-status
Swift 4 updated.

import UIKit

class DiskStatus {

    //MARK: Formatter MB only
    class func MBFormatter(_ bytes: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = ByteCountFormatter.Units.useMB
        formatter.countStyle = ByteCountFormatter.CountStyle.decimal
        formatter.includesUnit = false
        return formatter.string(fromByteCount: bytes) as String
    }


    //MARK: Get String Value
    class var totalDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: totalDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }

    class var freeDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }

    class var usedDiskSpace:String {
        get {
            return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
        }
    }


    //MARK: Get raw value
    class var totalDiskSpaceInBytes:Int64 {
        get {
            do {
                let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
                let space = (systemAttributes[FileAttributeKey.systemSize] as? NSNumber)?.int64Value
                return space!
            } catch {
                return 0
            }
        }
    }

    class var freeDiskSpaceInBytes:Int64 {
        get {
            do {
                let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
                let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value
                return freeSpace!
            } catch {
                return 0
            }
        }
    }

    class var usedDiskSpaceInBytes:Int64 {
        get {
            let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
            return usedSpace
        }
    }

}

Demo

get disk space status with Swift

Solution 4

If you need formatted string with size you can take a look at nice library on GitHub:

#define MB (1024*1024)
#define GB (MB*1024)

@implementation ALDisk

#pragma mark - Formatter

+ (NSString *)memoryFormatter:(long long)diskSpace {
    NSString *formatted;
    double bytes = 1.0 * diskSpace;
    double megabytes = bytes / MB;
    double gigabytes = bytes / GB;
    if (gigabytes >= 1.0)
        formatted = [NSString stringWithFormat:@"%.2f GB", gigabytes];
    else if (megabytes >= 1.0)
        formatted = [NSString stringWithFormat:@"%.2f MB", megabytes];
    else
        formatted = [NSString stringWithFormat:@"%.2f bytes", bytes];

    return formatted;
}

#pragma mark - Methods

+ (NSString *)totalDiskSpace {
    long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue];
    return [self memoryFormatter:space];
}

+ (NSString *)freeDiskSpace {
    long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue];
    return [self memoryFormatter:freeSpace];
}

+ (NSString *)usedDiskSpace {
    return [self memoryFormatter:[self usedDiskSpaceInBytes]];
}

+ (CGFloat)totalDiskSpaceInBytes {
    long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue];
    return space;
}

+ (CGFloat)freeDiskSpaceInBytes {
    long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue];
    return freeSpace;
}

+ (CGFloat)usedDiskSpaceInBytes {
    long long usedSpace = [self totalDiskSpaceInBytes] - [self freeDiskSpaceInBytes];
    return usedSpace;
}

Solution 5

Update with a new accurate API to get available size on disk available in iOS11. Here is the description for the new API resource key:

#if os(OSX) || os(iOS)
/// Total available capacity in bytes for "Important" resources, including space expected to be cleared by purging non-essential and cached resources. "Important" means something that the user or application clearly expects to be present on the local system, but is ultimately replaceable. This would include items that the user has explicitly requested via the UI, and resources that an application requires in order to provide functionality.
/// Examples: A video that the user has explicitly requested to watch but has not yet finished watching or an audio file that the user has requested to download.
/// This value should not be used in determining if there is room for an irreplaceable resource. In the case of irreplaceable resources, always attempt to save the resource regardless of available capacity and handle failure as gracefully as possible.
@available(OSX 10.13, iOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable)
public var volumeAvailableCapacityFor Usage: Int64? { return _get(.volumeAvailableCapacityForImportantUsageKey) }
#endif

I cross compared the results from key "FileAttributeKey.systemFreeSize" and key "URLResourceKey.volumeAvailableCapacityForImportantUsageKey" and found the results returned form "volumeAvailableCapacityForImportantUsageKey" exactly matches the available storage shown on UI. Available free disk space compare Here is the swift implementation:

class var freeDiskSpaceInBytesImportant:Int64 {
    get {
        do {
            return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage!
        } catch {
            return 0
        }
    }
}
Share:
89,750

Related videos on Youtube

Code.Decode
Author by

Code.Decode

Work - I like solving problems - especially with the kind of solution which makes tasks simpler and the user experience smoother. And I like to learn technologies that help me solve problems. At work, I like to contribute to the team to achieve a common goal. Fun - When I'm not working, I'm spending time with my family and helping community by volunteering. I like reading, studying and helping people.

Updated on December 01, 2021

Comments

  • Code.Decode
    Code.Decode over 2 years

    I'm looking for a better way to detect available/free disk space on the iPhone/iPad device programmatically.
    Currently I'm using the NSFileManager to detect the disk space. Following is the snippet of the code which does the job for me:

    -(unsigned)getFreeDiskspacePrivate {
    NSDictionary *atDict = [[NSFileManager defaultManager] attributesOfFileSystemForPath:@"/" error:NULL];
    unsigned freeSpace = [[atDict objectForKey:NSFileSystemFreeSize] unsignedIntValue];
    NSLog(@"%s - Free Diskspace: %u bytes - %u MiB", __PRETTY_FUNCTION__, freeSpace, (freeSpace/1024)/1024);
    
    return freeSpace;
    }
    


    Am I correct with the above snippet? or is there any better way to know total available/free disk space.
    I've to detect total free disk space, since we've to prevent our application to perform sync in the low disk space scenario.

  • David H
    David H about 12 years
    Its better than a tip - "Its the Law" :-) As he said, the original code is just plain wrong.
  • the Reverend
    the Reverend about 12 years
    I don't have experience with the new automatic counting system but Whats the __autoreleasing for? You normally don't need to autorelease the NSError returned
  • Fabian Kreiser
    Fabian Kreiser almost 12 years
  • Zennichimaro
    Zennichimaro about 11 years
    on my iPod Touch 4th Gen running iOS 5.1, NSFileSystemFreeSize is still reporting ~200 MBytes too much. I print out the content of the whole NSDictionary in debugger... NSFileSystemSize is correct though... anybody have solution for this problem?
  • Sudheer Kumar Palchuri
    Sudheer Kumar Palchuri over 10 years
    @Zennichimaro: Did you fix your problem? I am also facing the same issue, getting 0.2 GB extra when i check free space in iPad. iPad is showing 24.1 GB available space but in code it is showing 24.3 GB.
  • Zennichimaro
    Zennichimaro over 10 years
    @PalchuriSudheerKumar, I tried fstats and it is still giving the same issue so I think it is Apple's bug. I solve it by offsetting 300MBytes
  • David H
    David H about 10 years
    @Diejmon you cannot ask NSNumber for an integeral size of this type. This is why for such things I prefer a unit of known bit size. While technically I agree with your statement, I already have enough warnings to deal with using NSInteger and format strings! 64 bits will be enough bits for sure in my lifetime and yours.
  • Daniel Barden
    Daniel Barden about 9 years
    To format, one can also use NSBytCounterFormatter
  • Paulius Liekis
    Paulius Liekis about 9 years
    This is still prone to same +200MB bug: stackoverflow.com/questions/9270027/…
  • ChrisJF
    ChrisJF almost 7 years
    @JuanBoero Posted in Swift 3.1 (finally)!
  • rshev
    rshev over 6 years
    Where “opportunistic usage” is coming from on your screenshot?
  • rshev
    rshev over 6 years
    Found it, volumeAvailableCapacityForOpportunisticUsageKey.
  • kakaiikaka
    kakaiikaka over 6 years
    Yes rshev, volumeAvailableCapacityForOpportunisticUsageKey gets "“opportunistic usage" on my screenshot
  • Suryakant Sharma
    Suryakant Sharma about 6 years
    to see the available storage size should I query with NSHomeDirectory() or NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDi‌​rectory.documentDire‌​ctory, FileManager.SearchPathDomainMask.userDomainMask, true). Is there any difference using these two?
  • TheTiger
    TheTiger about 6 years
    Do not use ! instead put a guard to safe typecasting or nil check.
  • abdullahselek
    abdullahselek about 6 years
    Thanks for your comments @TheTiger.

Related