[英]Query Available iOS Disk Space with Swift
我正在嘗試使用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
}
但是在編譯時給出了這個錯誤: [NSObject : AnyObject]? does not have a member named 'subscript'
[NSObject : AnyObject]? does not have a member named 'subscript'
我相信這個錯誤是由這里提到的問題引起的,即attributesOfFileSystemForPath
返回一個可選的字典( 文檔)。 我從一般意義上理解這個問題,但由於建議的解決方案涉及嵌套案例,我不太明白如何修復我感興趣的函數(我對Swift
很陌生,這無濟於事) . 有人可以建議如何使該功能正常工作嗎? 注意:我不確定原始功能是否由作者測試過,或者它是否在 xcode 6 beta 下工作,但據我所知,它在 GM 下不起作用。
下面給出的答案在 iOS 11 下不再提供准確的結果。有新的卷容量鍵可以傳遞給URL.resourceValues(forKeys:)
,提供與設備設置中可用的值相匹配的值。
static let volumeAvailableCapacityKey: URLResourceKey
以字節為單位的卷可用容量的密鑰(只讀)。
static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey
用於存儲重要資源的卷可用容量的密鑰(只讀)。
static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey
用於存儲非必要資源的卷可用容量的密鑰(以字節為單位)(只讀)。
static let volumeTotalCapacityKey: URLResourceKey
以字節為單位的卷總容量的密鑰(只讀)。
來自蘋果的文檔:
概述
在嘗試在本地存儲大量數據之前,請先驗證您是否有足夠的存儲容量。 要獲取卷的存儲容量,您可以構造一個 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)")
}
與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
}
斯威夫特 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
}
斯威夫特 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
}
用法:
if let bytes = deviceRemainingFreeSpaceInBytes() {
print("free space: \(bytes)")
} else {
print("failed")
}
好吧,根據上面的代碼:
let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
您可能會發現usedSpace不等於 iPhone 設置頁面的值。 那是因為在 iOS11 中,Apple為“重要”資源引入了以字節為單位的可用容量。
“重要”資源的總可用容量(以字節為單位),包括預計通過清除非必要和緩存資源來清除的空間。 “重要”是指用戶或應用程序明確希望出現在本地系統上,但最終是可替換的。 這將包括用戶通過 UI 明確請求的項目,以及應用程序提供功能所需的資源。
示例:用戶明確請求觀看但尚未完成觀看的視頻或用戶請求下載的音頻文件。
該值不應用於確定是否有不可替代資源的空間。 對於不可替代的資源,無論可用容量如何,始終嘗試保存資源並盡可能優雅地處理故障。
為了獲得與我們在 iPhone 設置頁面看到的完全相同的值,我們可以通過volumeAvailableCapacityForImportantUsage獲取可用空間
if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
return space ?? 0
}
您可以使用以下UIDevice 擴展:
斯威夫特4
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
}
}
用法:
print("totalDiskSpaceInBytes: \(UIDevice.current.totalDiskSpaceInBytes)")
print("freeDiskSpace: \(UIDevice.current.freeDiskSpaceInBytes)")
print("usedDiskSpace: \(UIDevice.current.usedDiskSpaceInBytes)")
我編寫了一個類來使用 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
}
}
}
演示:
這類似於 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
}
}
獲取可用空間:
UIDevice.current.systemFreeSize
並獲得總空間:
UIDevice.current.systemSize
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.