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 s
Swift 5 extension for FileManager
with proper error handling and no automatic string conversions (convert byte count to string as you prefer). Also follows FileManager
's naming.
extension FileManager {
func systemFreeSizeBytes() -> Result<Int64, Error> {
do {
let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
guard let freeSize = attrs[.systemFreeSize] as? Int64 else {
return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system free size"]))
}
return .success(freeSize)
} catch {
return .failure(error)
}
}
func systemSizeBytes() -> Result<Int64, Error> {
do {
let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
guard let size = attrs[.systemSize] as? Int64 else {
return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system size"]))
}
return .success(size)
} catch {
return .failure(error)
}
}
}
Example usage:
let freeSizeResult = FileManager.default.systemFreeSizeBytes()
switch freeSizeResult {
case .failure(let error):
print(error)
case .success(let freeSize):
let freeSizeString = ByteCountFormatter.string(fromByteCount: freeSize, countStyle: .file)
print("free size: \(freeSizeString)")
}
Don't use 'unsigned', it is only 32 bits which will overflow past 4GB, which is less than the typical iPad/iPhone free space. Use unsigned long long (or uint64_t), and retrieve the value out of the NSNumber as a 64-bit int too using unsignedLongLongValue.
for Swift as UIDevice extension
extension UIDevice {
func freeDiskspace() -> NSString {
let failedResult: String = "Error Obtaining System Memory"
guard let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last else {
return failedResult
}
do {
let dictionary = try NSFileManager.defaultManager().attributesOfFileSystemForPath(path)
if let fileSystemSizeInBytes = dictionary[NSFileSystemSize] as? UInt,
let freeFileSystemSizeInBytes = dictionary[NSFileSystemFreeSize] as? UInt {
return "Memory \(freeFileSystemSizeInBytes/1024/1024) of \(fileSystemSizeInBytes/1024/1024) Mb available."
} else {
return failedResult
}
} catch {
return failedResult
}
}
}
How to use:
print("\(UIDevice.currentDevice().freeDiskspace())")
Output will be:
Memory 9656 of 207694 Mb available.
ChrisJF answer in Swift 2.1 version:
func freeSpaceInBytes() -> NSString{
var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.")
do {
let dictionary = try NSFileManager.defaultManager().attributesOfFileSystemForPath(NSHomeDirectory())
freeSpaceSize = (dictionary[NSFileSystemFreeSize]?.longLongValue)!
remainingSpace = NSByteCountFormatter.stringFromByteCount(freeSpaceSize, countStyle: NSByteCountFormatterCountStyle.File)
}
catch let error as NSError {
error.description
NSLog(error.description)
}
return remainingSpace
}
If your looking to get the the remaining free space using Swift it is slightly different. You need to use attributesOfFileSystemForPath() instead of attributesOfItemAtPath():
func deviceRemainingFreeSpaceInBytes() -> Int64? {
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var attributes: [String: AnyObject]
do {
attributes = try NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last! as String)
let freeSize = attributes[NSFileSystemFreeSize] as? NSNumber
if (freeSize != nil) {
return freeSize?.longLongValue
} else {
return nil
}
} catch {
return nil
}
}
Edit: Updated for Swift 1.0
Edit 2: Updated for safety, using Martin R's answer.
Edit 3: Updated for Swift 2.0 (by dgellow)
For iOS >= 6.0 you can use the new NSByteCountFormatter. This code gets the number of free bytes remaining as a formatted string.
NSError *error = nil;
NSArray * const paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSDictionary * const pathAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths firstObject] error:&error];
NSAssert(pathAttributes, @"");
NSNumber * const fileSystemSizeInBytes = [pathAttributes objectForKey: NSFileSystemFreeSize];
const long long numberOfBytesRemaining = [fileSystemSizeInBytes longLongValue];
NSByteCountFormatter *byteCountFormatter = [[NSByteCountFormatter alloc] init];
NSString *formattedNmberOfBytesRemaining = [byteCountFormatter stringFromByteCount:numberOfBytesRemaining];