How to get iPad / iPhone app size programmatically in Swift

So, I am trying to get the size of my application programmatically. The app is downloading a large number of audio files and I am trying to verify that when the files are deleted, the size of the app shrinks as expected. So far, the only way I know how to do this is by looking at the iPad settings, but the numbers there don't seem to always be correct.

func getAppSize(){
    let paths : NSArray = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)
    var errorP = NSErrorPointer()
    let pathDictionary: NSDictionary = NSFileManager.defaultManager().attributesOfFileSystemForPath(paths.firstObject as String, error: errorP)!
    if(pathDictionary.count != 0){
        var fileSystemSizeInBytes: Double = pathDictionary.objectForKey("NSFileSystemSize") as Double
        var fileSystemSizeInMegaBytes : Double = fileSystemSizeInBytes/1000000
        println("Total Space: \(fileSystemSizeInMegaBytes) MB")
    }else{

    }
}

      

I am currently just using File-System Attirbute Key for the file system size which I expected to be the size of my current application, but since it returns 249GB its obvious reading my entire MacBook file system, not the simulator document path ...

I looked through other attribute key options and found:

let NSFileSystemSize: NSString!
let NSFileSystemFreeSize: NSString!
let NSFileSystemNodes: NSString!
let NSFileSystemFreeNodes: NSString!
let NSFileSystemNumber: NSString!

      

However, I have not found a key that determines the size of the actual space my application is occupying. I think maybe there is a way to get all the nodes and then add their sizes, but I'm not really sure how.

Thank you in advance

EDIT: So the package seems to give me the size of my applications, but without any mp3 files that I save in the document path. I'm guessing I could save them in the wrong place or something, here is a simplified version of how I save them in the application.

//Make HTTP Request Ect... before here...
if(data.length > 1000){
    let documentPath = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)
    let uuid = NSUUID().UUIDString
    let localUrl = uuid + ".mp3"
    let destPath = (documentPath[0] as String) + "/" + localUrl
    data.writeToFile(destPath, atomically: true)
    var error: NSErrorPointer = nil
    data.writeToFile(destPath, options: NSDataWritingOptions.DataWritingAtomic, error: error)
    if(error != nil){
        println("data write error: \(error.memory?.localizedDescription)")
    }
}

      

+3


source to share


4 answers


According to the documents , "The file systems in OS X and iOS handle persistent storage of data files, applications and their associated files with the operating system itself." Also according to the docs , "An NSBundle object represents a location in the filesystem that groups code and resources that can be used in a program," so your main application bundle is where its files live. And according to this link , every iOS app consists of a package, document directory, library and tmp.

To get the overall size of your application, list through bundle, docs, library and tmp subtypes, for example:



func appSize() {

    // Go through the app bundle
    let bundlePath = NSBundle.mainBundle().bundlePath
    let bundleArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(bundlePath, error: nil)!
    let bundleEnumerator = bundleArray.objectEnumerator()
    var fileSize: UInt64 = 0

    while let fileName:String = bundleEnumerator.nextObject() as? String {
        let fileDictionary:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(bundlePath.stringByAppendingPathComponent(fileName), error: nil)!
        fileSize += fileDictionary.fileSize();
    }

    // Go through the app document directory
    let documentDirectory:NSArray = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)
    let documentDirectoryPath:NSString = documentDirectory[0] as NSString
    let documentDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(documentDirectoryPath, error: nil)!
    let documentDirectoryEnumerator = documentDirectoryArray.objectEnumerator()

    while let file:String = documentDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(documentDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    // Go through the app library directory
    let libraryDirectory:NSArray = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    let libraryDirectoryPath:NSString = libraryDirectory[0] as NSString
    let libraryDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(libraryDirectoryPath, error: nil)!
    let libraryDirectoryEnumerator = libraryDirectoryArray.objectEnumerator()

    while let file:String = libraryDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(libraryDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    // Go through the app tmp directory
    let tmpDirectoryPath:NSString = NSTemporaryDirectory()
    let tmpDirectoryArray:NSArray = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(tmpDirectoryPath, error: nil)!
    let tmpDirectoryEnumerator = tmpDirectoryArray.objectEnumerator()

    while let file:String = tmpDirectoryEnumerator.nextObject() as? String {
        let attributes:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(tmpDirectoryPath.stringByAppendingPathComponent(file), error: nil)!
        fileSize += attributes.fileSize();
    }

    var fileSystemSizeInMegaBytes : Double = Double(fileSize)/1000000
    println("Total App Space: \(fileSystemSizeInMegaBytes) MB")
}

      

+3


source


You calculate the size of the Library folder. Not the size of your app directory folder.

According to NSSearchPathDirectory :

NSLibraryDirectory

Various user-visible documents, support files, and configuration files (/ Library).

Available in iOS 2.0 and later.

You have to modify your file to save and calculate the code:



Preservation:

//Make HTTP Request Ect... before here...
if(data.length > 1000)
{
    let documentPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let uuid = NSUUID().UUIDString
    let localUrl = uuid + ".mp3"
    let destPath = (documentPath[0] as String) + "/" + localUrl
    data.writeToFile(destPath, atomically: true)
    var error: NSErrorPointer = nil
    data.writeToFile(destPath, options: NSDataWritingOptions.DataWritingAtomic, error: error)
    if(error != nil){
        println("data write error: \(error.memory?.localizedDescription)")
    }
}

      

Calculation:

func getAppSize()
{
    let paths : NSArray   = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let path : NSString   = paths.firstObject? as NSString
    let files : NSArray   = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(path, error: nil)!
    let dirEnumerator     = files.objectEnumerator()
    var totalSize: UInt64 = 0
    let fileManager       = NSFileManager.defaultManager();
    while let file:String = dirEnumerator.nextObject() as? String
    {
        let attributes:NSDictionary = fileManager.attributesOfItemAtPath(path.stringByAppendingPathComponent(file), error: nil)!
        totalSize += attributes.fileSize();
    }

    var fileSystemSizeInMegaBytes : Double = Double(totalSize)/1000000
    println("Total Space: \(fileSystemSizeInMegaBytes) MB")
}

      

+2


source


Updated and refactored @ lyndsey-scott's answer for Swift 3 . I modified the code to return the megabyte size as Float64 instead of printing it to the console as that was fine for my purposes.

private class func appSizeInMegaBytes() -> Float64 { // approximate value

    // create list of directories
    var paths = [Bundle.main.bundlePath] // main bundle
    let docDirDomain = FileManager.SearchPathDirectory.documentDirectory
    let docDirs = NSSearchPathForDirectoriesInDomains(docDirDomain, .userDomainMask, true)
    if let docDir = docDirs.first {
        paths.append(docDir) // documents directory
    }
    let libDirDomain = FileManager.SearchPathDirectory.libraryDirectory
    let libDirs = NSSearchPathForDirectoriesInDomains(libDirDomain, .userDomainMask, true)
    if let libDir = libDirs.first {
        paths.append(libDir) // library directory
    }
    paths.append(NSTemporaryDirectory() as String) // temp directory

    // combine sizes
    var totalSize: Float64 = 0
    for path in paths {
        if let size = bytesIn(directory: path) {
            totalSize += size
        }
    }
    return totalSize / 1000000 // megabytes
}

private class func bytesIn(directory: String) -> Float64? {
    let fm = FileManager.default
    guard let subdirectories = try? fm.subpathsOfDirectory(atPath: directory) as NSArray else {
        return nil
    }
    let enumerator = subdirectories.objectEnumerator()
    var size: UInt64 = 0
    while let fileName = enumerator.nextObject() as? String {
        do {
            let fileDictionary = try fm.attributesOfItem(atPath: directory.appending("/" + fileName)) as NSDictionary
            size += fileDictionary.fileSize()
        } catch let err {
            print("err getting attributes of file \(fileName): \(err.localizedDescription)")
        }
    }
    return Float64(size)
}

      

+2


source


What do you mean by application size?
If you are concerned about the amount of data you download from the web, it is best practice to download the catalog Cache

and be ready to check out when the system is required. Or you can store them in a directory Documents

and pay attention to adding a "no backup" attribute to the downloaded files, or your application is likely to be rejected.

0


source







All Articles