使用Swift查询可用的iOS磁盘空间

Bry*_*son 23 storage ios swift

我正在尝试使用可用的iOS设备存储Swift.我在这里找到了这个功能

        func deviceRemainingFreeSpaceInBytes() -> NSNumber {
          let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
          let systemAttributes = NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last as String, error: nil)
          return systemAttributes[NSFileSystemFreeSize] as NSNumber
        }
Run Code Online (Sandbox Code Playgroud)

但是在编译时给出了这个错误:[NSObject : AnyObject]? does not have a member named 'subscript' 我认为这个错误来自这里提到的问题,即attributesOfFileSystemForPath返回一个可选的字典(文档).我在一般意义上理解这个问题,但是由于建议的解决方案涉及嵌套的情况,我不太清楚如何修复我感兴趣的函数(这对我来说并不是很有帮助Swift).有人可以建议如何使功能工作?注意:我不确定作者是否测试了原始函数,或者它是否在xcode 6 beta下运行,但据我所知,它在GM下无效.

Mar*_*n R 54

iOS 11更新

下面给出的答案不再能够在iOS 11下提供准确的结果.可以传递新的卷容量键URL.resourceValues(forKeys:),提供与设备设置中可用的值相匹配的值.

  • static let volumeAvailableCapacityKey: URLResourceKey 卷的可用容量的密钥(以字节为单位)(只读).

  • static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey 用于存储重要资源的卷的可用容量(以字节为单位)的密钥(只读).

  • static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey 用于存储非必要资源的卷的可用容量(以字节为单位)的密钥(只读).

  • static let volumeTotalCapacityKey: URLResourceKey 卷的总容量的密钥(以字节为单位)(只读).

来自Apple的文档:

概观

在尝试在本地存储大量数据之前,请先验证您是否具有足够的存储容量.要获取卷的存储容量,请构造一个URL(使用URL实例),该URL引用要查询的卷上的对象,然后查询该卷.

确定要使用的查询类型

要使用的查询类型取决于存储的内容.如果您要根据应用程序正常运行的用户请求或资源存储数据(例如,用户即将观看的视频或游戏中下一级所需的资源),请查询volumeAvailableCapacityForImportantUsageKey.但是,如果您以更具预测性的方式下载数据(例如,下载用户最近一直在观看的电视连续剧的新可用剧集),请查询volumeAvailableCapacityForOpportunisticUsageKey.

构造一个查询

使用此示例作为构建您自己的查询的指南:

let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String)
do {
    let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
    if let capacity = values.volumeAvailableCapacityForImportantUsage {
        print("Available capacity for important usage: \(capacity)")
    } else {
        print("Capacity is unavailable")
    }
} catch {
    print("Error retrieving capacity: \(error.localizedDescription)")
}
Run Code Online (Sandbox Code Playgroud)

原始答案

可选的结合if let作品在这里.

我建议该函数返回一个可选项Int64,以便它可以返回 nil发出故障信号:

func deviceRemainingFreeSpaceInBytes() -> Int64? {
    let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    if let systemAttributes = NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last as String, error: nil) {
        if let freeSize = systemAttributes[NSFileSystemFreeSize] as? NSNumber {
            return freeSize.longLongValue
        }
    }
    // something failed
    return nil
}
Run Code Online (Sandbox Code Playgroud)

Swift 2.1更新:

func deviceRemainingFreeSpaceInBytes() -> Int64? {
    let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
    guard
        let systemAttributes = try? NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectory),
        let freeSize = systemAttributes[NSFileSystemFreeSize] as? NSNumber
    else {
        // something failed
        return nil
    }
    return freeSize.longLongValue
}
Run Code Online (Sandbox Code Playgroud)

Swift 3.0更新:

func deviceRemainingFreeSpaceInBytes() -> Int64? {
    let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
    guard
        let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: documentDirectory),
        let freeSize = systemAttributes[.systemFreeSize] as? NSNumber
    else {
        // something failed
        return nil
    }
    return freeSize.int64Value
}
Run Code Online (Sandbox Code Playgroud)

用法:

if let bytes = deviceRemainingFreeSpaceInBytes() {
    print("free space: \(bytes)")
} else {
    print("failed")
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这些返回约.200mb(200495104)的免费空间.虽然iOS不允许我拍任何照片,但我无法将7mb视频保存到磁盘? (3认同)
  • 正如@LucèBrùlè所提到的,当我运行上面的代码时,同样的事情就是这样.显示大约215089152个字节.但当我检查显示几个字节的应用程序存储.任何方式找出确切的,就像在应用程序存储设置中显示一样?提前致谢 (2认同)

DàC*_*hún 24

那么,根据上面的代码:

let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
Run Code Online (Sandbox Code Playgroud)

您可能会发现usedSpace不等于iPhone设置页面的值.这是因为在iOS11中,Apple 为"重要"资源引入了总可用容量(以字节为单位).

"重要"资源的总可用容量(以字节为单位),包括通过清除非必要资源和缓存资源来清除的空间."重要"是指用户或应用程序明确希望在本地系统上出现的内容,但最终可以替换.这将包括用户通过UI明确请求的项目,以及应用程序为提供功能所需的资源.

示例:用户已明确请求观看但尚未观看的视频或用户请求下载的音频文件.

此值不应用于确定是否存在不可替代资源的空间.在不可替代资源的情况下,始终尝试保存资源而不管可用容量如何,并尽可能优雅地处理故障.

为了获得与我们在iPhone设置页面中看到的完全相同的值,我们可以通过volumeAvailableCapacityForImportantUsage获得可用空间

if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
    return space ?? 0
}
Run Code Online (Sandbox Code Playgroud)

您可以使用以下UIDevice扩展:

Swift4

extension UIDevice {
    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
    var totalDiskSpaceInGB:String {
       return ByteCountFormatter.string(fromByteCount: totalDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
    }

    var freeDiskSpaceInGB:String {
        return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
    }

    var usedDiskSpaceInGB:String {
        return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
    }

    var totalDiskSpaceInMB:String {
        return MBFormatter(totalDiskSpaceInBytes)
    }

    var freeDiskSpaceInMB:String {
        return MBFormatter(freeDiskSpaceInBytes)
    }

    var usedDiskSpaceInMB:String {
        return MBFormatter(usedDiskSpaceInBytes)
    }

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

    /*
     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.
     */
    var freeDiskSpaceInBytes:Int64 {
        if #available(iOS 11.0, *) {
            if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
                return space ?? 0
            } else {
                return 0
            }
        } else {
            if let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
            let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value {
                return freeSpace
            } else {
                return 0
            }
        }
    }

    var usedDiskSpaceInBytes:Int64 {
       return totalDiskSpaceInBytes - freeDiskSpaceInBytes
    }

}
Run Code Online (Sandbox Code Playgroud)

用法:

Logger.d("totalDiskSpaceInBytes: \(UIDevice.current.totalDiskSpaceInBytes)")
Logger.d("freeDiskSpace: \(UIDevice.current.freeDiskSpaceInBytes)")
Logger.d("usedDiskSpace: \(UIDevice.current.usedDiskSpaceInBytes)")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 这应该是 2018 年的最佳答案。 (2认同)

Cuo*_*Lam 20

我已经编写了一个类来使用Swift获取/使用内存.演示:https://github.com/thanhcuong1990/swift-disk-status

升级以支持Swift 3.

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.binary)
        }
    }

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

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


    //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
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

演示:

使用Swift获取磁盘空间状态

  • 不幸的是,该值与 iPhone 关于页面上的值不同 (2认同)