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

时间:2021-08-19 16:51:54

I'm trying to get the available iOS device storage using Swift. I found this function here

我正在尝试使用Swift获取可用的iOS设备存储空间。我在这里找到了这个功能

        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
        }

But at compile time this error is given: [NSObject : AnyObject]? does not have a member named 'subscript' I believe this error arises from the issue mentioned here, namely that attributesOfFileSystemForPath returns an optional dictionary (documentation). I understand the problem in a general sense, but because the suggested solution involves a nested case, I don't quite see how to fix the function I'm interested in (it doesn't help that I'm quite new to Swift). Can someone suggest how to make the function work? NOTE: I'm not sure if the original function was tested by the author or if it worked under an xcode 6 beta, but it doesn't work under the GM as far as I can see.

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

4 个解决方案

#1


32  

iOS 11 Update

The answers given below no longer provide accurate results under iOS 11. There are new volume capacity keys that can be passed to URL.resourceValues(forKeys:) that provide values that match what is available in device settings.

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

  • static let volumeAvailableCapacityKey: URLResourceKey Key for the volume’s available capacity in bytes (read-only).

    static let volumeAvailableCapacityKey:URLResourceKey卷的可用容量的字符串(以字节为单位)(只读)。

  • static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey Key for the volume’s available capacity in bytes for storing important resources (read-only).

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

  • static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey Key for the volume’s available capacity in bytes for storing nonessential resources (read-only).

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

  • static let volumeTotalCapacityKey: URLResourceKey Key for the volume’s total capacity in bytes (read-only).

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

From Apple's documentation:

来自Apple的文档:

Overview

Before you try to store a large amount of data locally, first verify that you have sufficient storage capacity. To get the storage capacity of a volume, you construct a URL (using an instance of URL) that references an object on the volume to be queried, and then query that volume.

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

Decide Which Query Type to Use

The query type to use depends on what's being stored. If you’re storing data based on a user request or resources the app requires to function properly (for example, a video the user is about to watch or resources that are needed for the next level in a game), query against volumeAvailableCapacityForImportantUsageKey. However, if you’re downloading data in a more predictive manner (for example, downloading a newly available episode of a TV series that the user has been watching recently), query against volumeAvailableCapacityForOpportunisticUsageKey.

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

Construct a Query

Use this example as a guide to construct your own query:

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

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)")
}

Original Answer

Optional binding with if let works here as well.

使用if的可选绑定也适用于此处。

I would suggest that the function returns an optional Int64, so that it can return nil to signal a failure:

我建议函数返回一个可选的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
}

Swift 2.1 Update:

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
}

Swift 3.0 Update:

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
}

Usage:

用法:

if let bytes = deviceRemainingFreeSpaceInBytes() {
    print("free space: \(bytes)")
} else {
    print("failed")
}

#2


19  

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

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

Upgrade to support Swift 3.

升级以支持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
        }
    }

}

Demo:

演示:

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

#3


12  

Well, according to the above codes:

那么,根据上面的代码:

let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes

you might find out that usedSpace doesn't equal the value of iPhone setting page. That is because in iOS11, Apple introduces Total available capacity in bytes for "Important" resources.

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

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.

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

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.

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

In order to get the exact same value as what we see in iPhone setting page, we can get free space by volumeAvailableCapacityForImportantUsage

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

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

You can use the following UIDevice extension:

您可以使用以下UIDevice扩展:

Swift4

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
    }

}

usage:

用法:

Logger.d("totalDiskSpaceInBytes: \(UIDevice.current.totalDiskSpaceInBytes)")
Logger.d("freeDiskSpace: \(UIDevice.current.freeDiskSpaceInBytes)")
Logger.d("usedDiskSpace: \(UIDevice.current.usedDiskSpaceInBytes)")

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

#4


2  

This is similar to Martin's answer for Swift 3.1, but is converted to an extension of UIDevice to make accessing it easier.

这类似于Martin对Swift 3.1的回答,但是转换为UIDevice的扩展,以便更容易地访问它。

extension UIDevice {
    var systemSize: Int64? {
        guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
            let totalSize = (systemAttributes[.systemSize] as? NSNumber)?.int64Value else {
                return nil
        }

        return totalSize
    }

    var systemFreeSize: Int64? {
        guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
            let freeSize = (systemAttributes[.systemFreeSize] as? NSNumber)?.int64Value else {
                return nil
        }

        return freeSize
    }
}

To get free space:

获得*空间:

UIDevice.current.systemFreeSize

And to get total space:

并获得总空间:

UIDevice.current.systemSize

#1


32  

iOS 11 Update

The answers given below no longer provide accurate results under iOS 11. There are new volume capacity keys that can be passed to URL.resourceValues(forKeys:) that provide values that match what is available in device settings.

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

  • static let volumeAvailableCapacityKey: URLResourceKey Key for the volume’s available capacity in bytes (read-only).

    static let volumeAvailableCapacityKey:URLResourceKey卷的可用容量的字符串(以字节为单位)(只读)。

  • static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey Key for the volume’s available capacity in bytes for storing important resources (read-only).

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

  • static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey Key for the volume’s available capacity in bytes for storing nonessential resources (read-only).

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

  • static let volumeTotalCapacityKey: URLResourceKey Key for the volume’s total capacity in bytes (read-only).

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

From Apple's documentation:

来自Apple的文档:

Overview

Before you try to store a large amount of data locally, first verify that you have sufficient storage capacity. To get the storage capacity of a volume, you construct a URL (using an instance of URL) that references an object on the volume to be queried, and then query that volume.

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

Decide Which Query Type to Use

The query type to use depends on what's being stored. If you’re storing data based on a user request or resources the app requires to function properly (for example, a video the user is about to watch or resources that are needed for the next level in a game), query against volumeAvailableCapacityForImportantUsageKey. However, if you’re downloading data in a more predictive manner (for example, downloading a newly available episode of a TV series that the user has been watching recently), query against volumeAvailableCapacityForOpportunisticUsageKey.

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

Construct a Query

Use this example as a guide to construct your own query:

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

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)")
}

Original Answer

Optional binding with if let works here as well.

使用if的可选绑定也适用于此处。

I would suggest that the function returns an optional Int64, so that it can return nil to signal a failure:

我建议函数返回一个可选的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
}

Swift 2.1 Update:

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
}

Swift 3.0 Update:

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
}

Usage:

用法:

if let bytes = deviceRemainingFreeSpaceInBytes() {
    print("free space: \(bytes)")
} else {
    print("failed")
}

#2


19  

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

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

Upgrade to support Swift 3.

升级以支持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
        }
    }

}

Demo:

演示:

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

#3


12  

Well, according to the above codes:

那么,根据上面的代码:

let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes

you might find out that usedSpace doesn't equal the value of iPhone setting page. That is because in iOS11, Apple introduces Total available capacity in bytes for "Important" resources.

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

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.

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

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.

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

In order to get the exact same value as what we see in iPhone setting page, we can get free space by volumeAvailableCapacityForImportantUsage

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

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

You can use the following UIDevice extension:

您可以使用以下UIDevice扩展:

Swift4

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
    }

}

usage:

用法:

Logger.d("totalDiskSpaceInBytes: \(UIDevice.current.totalDiskSpaceInBytes)")
Logger.d("freeDiskSpace: \(UIDevice.current.freeDiskSpaceInBytes)")
Logger.d("usedDiskSpace: \(UIDevice.current.usedDiskSpaceInBytes)")

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

#4


2  

This is similar to Martin's answer for Swift 3.1, but is converted to an extension of UIDevice to make accessing it easier.

这类似于Martin对Swift 3.1的回答,但是转换为UIDevice的扩展,以便更容易地访问它。

extension UIDevice {
    var systemSize: Int64? {
        guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
            let totalSize = (systemAttributes[.systemSize] as? NSNumber)?.int64Value else {
                return nil
        }

        return totalSize
    }

    var systemFreeSize: Int64? {
        guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
            let freeSize = (systemAttributes[.systemFreeSize] as? NSNumber)?.int64Value else {
                return nil
        }

        return freeSize
    }
}

To get free space:

获得*空间:

UIDevice.current.systemFreeSize

And to get total space:

并获得总空间:

UIDevice.current.systemSize