5

I read a lot of info about it, made some tests and get wrong results and I feel I'm missing something. The only info I'm getting and it's right info : the DEVICE free space / total space.

But I need only the info about the my APP. so :

  1. How to get the iOS application storage size. that display on settings. (not others apps, the current app)
  2. How to delete all cached / tmp / other files, so the storage size will be the same size like it was when first installed ?

Thanks.

user1105951
  • 2,259
  • 2
  • 34
  • 55
  • iOS Apps have their own sandbox and write to their own Documents Directory. Just delete the contents of your App's documents directory and that will clear it all for you. And what do you mean by "Application storage size"? – NSNoob Nov 17 '16 at 12:09
  • When you go to the Settings app, Storage & iCloud Usage, then you see list of apps and the storage size they take. I want to get in code, the value of my app storage size. About what you said on Documents Directory, I'm not sure it enough. meaning- If I delete document folder, the app storage size will not be the same as first install (or even close). there is also cache folder and other. this is why I'm asking here, maybe someone know the complete list of folder to delete. – user1105951 Nov 17 '16 at 12:27
  • for clearing all data you can use folderPath. Follow http://stackoverflow.com/a/9358551/5215474 – Saranjith Nov 25 '16 at 08:45

2 Answers2

0

For the first question, the code below would work. But I don't know if this method conforms Apple's API usage.

// Get block size on user partition.
struct statfs *mntbufp = NULL;
getmntinfo(&mntbufp, 0);

int i, count = 0;
unsigned int blockSize;

count = getmntinfo(&mntbufp, 0);

for (i = 0; i < count; ++i)
{
    // Find users partition.
    if (strcmp(mntbufp[i].f_mntonname, "/private/var") == 0) {
        blockSize = mntbufp[i].f_bsize;
        break;
    }
}

//get full pathname of bundle directory
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];

//get paths of all of the contained subdirectories
NSArray *bundleArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:bundlePath error:nil];

//to access each object in array
NSEnumerator *filesEnumerator = [bundleArray objectEnumerator];

NSString *fileName;

unsigned long long int fileSize = 0;
unsigned long long int filesSize = 0;
unsigned long long int sizeOnDisk = 0;

NSError *error = nil;

//return next object from enumerator
while (fileName = [filesEnumerator nextObject]) {
    NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[bundlePath stringByAppendingPathComponent:fileName] error:&error];

    fileSize = [fileDictionary fileSize];

    // File size is sum of all file sizes.
    filesSize += fileSize;

    // Calculate size on disk.
    sizeOnDisk += ceil((double)fileSize / blockSize) * blockSize;
}

// Find sandbox path.
NSString *sandboxPath = NSHomeDirectory();
NSArray *sandboxArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:sandboxPath error:nil];
filesEnumerator = [sandboxArray objectEnumerator];

while (fileName = [filesEnumerator nextObject]) {
    NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[sandboxPath stringByAppendingPathComponent:fileName] error:&error];

    fileSize = [fileDictionary fileSize];

    filesSize += fileSize;
    sizeOnDisk += ceil((double)fileSize / blockSize) * blockSize;
}

//converts a byte count value into a textual representation that is formatted with the appropriate byte modifier (KB, MB, GB and so on)
NSString *fileSizeStr = [NSByteCountFormatter stringFromByteCount:filesSize countStyle:NSByteCountFormatterCountStyleBinary];
NSString *sizeOnDiskStr = [NSByteCountFormatter stringFromByteCount:sizeOnDisk countStyle:NSByteCountFormatterCountStyleBinary];`

This calculates the size of the whole bundle. Part of the credit goes to 1218GG in this stackoverflow question. But his method does not count in binary format (iOS uses binary system; Mac OS 10.6 and later uses base 10 system. See this article), and does not count in size of sandbox files. I've modified/added the corresponding code.

Here is comparison between file size iOS app calculates and the one Mac finder displays (Finder Display vs. App Calculation):

61,801 B vs. 61 KB; 668 KB (637,472 B) vs. 623 KB; 13.5 MB (13,520,085 B) vs. 13.4 MB

There are some variations. May due to the difference between how Mac OS calculates file size and iOS calculates the file size. On iPhone runnig iOS 9, system shows 204 KB, while my method counts 208 KB. When app size is larger than 10 MB, the variation could be ignored.

Community
  • 1
  • 1
Zhigang An
  • 296
  • 2
  • 13
  • It seems that what iOS system shows is the "size on disk" instead of "file size". So the conversion between file size and sizeOnDisk is necessary. Current app storage is `sizeOnDisk`. – Zhigang An Nov 26 '16 at 08:05
-1

You can use this to find cached documents in your app and then remove them:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);    
NSString *firstPath = paths[0];
NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:firstPath error:nil];
NSEnumerator *contentsEnumurator = [contents objectEnumerator];        
NSString *file;

unsigned long long int folderSize = 0;

while (file = [contentsEnumurator nextObject]) {

    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[firstPath stringByAppendingPathComponent:file] error:nil];
    folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];

}

folderSize = folderSize / 1000.0f / 1000.0f; // Folder size in MB (more pressition folderSize/1024.0f/1024.0f);

NSMutableArray *filesToRemove = [[NSMutableArray alloc] init];
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:firstPath error:NULL];

for (NSString *path in files) {

   BOOL isDir;
   NSString *filePath = [[[self class] cachesDirectoryPath] stringByAppendingPathComponent:path];
   BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDir];

   if (fileExists && !isDir) {

       NSString *filePath = [NSString stringWithFormat:@"%@/%@", firstPath ,path];
       NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath: filePath error:NULL];
       NSDictionary *fileDescription = [[NSDictionary alloc] init];

       @try {
           //Adds the file description to the files to remove
           fileDescription = @{
                               @"kFilePath": filePath,
                               @"kFileSize": [attr objectForKey:NSFileSize],
                               @"kFileModificationDate": [attr objectForKey:NSFileModificationDate]
                              };
       } @catch (NSException *exception) {
           NSLog(@"File description problem");
       }

       if (fileDescription.allKeys.count > 0) {
          [filesToRemove addObject:fileDescription];
       }
    }
}
float removedMB = 0;

for (NSDictionary *fileDescription in filesToRemove) {
    NSLog(@"Removing file: %@", [fileDescription objectForKey:@"kFilePath"]);
    removedMB += [( (NSNumber *)[fileDescription objectForKey:@"kFileSize"] ) floatValue] / 1000.0f / 1000.0f;
    NSError *error = nil;
    [[NSFileManager defaultManager] removeItemAtPath:[fileDescription objectForKey:@"kFilePath"] error:&error];
}

NSLog(@"Removed MB: %f", removedMB);