簡體   English   中英

使用 Swift 查詢可用的 iOS 磁盤空間

[英]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 更新

下面給出的答案在 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
        }
    }

}

演示:

使用 Swift 獲取磁盤空間狀態

這類似於 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM