希紋的部落格

剩餘儲存空間查詢

在做和檔案相關的處理時就會需要判斷儲存空間夠不夠,比如說下載、解壓縮。

查詢的時候AI還沒有普及,就是靠StackOverFlow看有沒有人問過這些問題,像這個問題2014年就有人問過,查詢這個問題的時候是2023年。跟AI的差別在「人家的答案」不一定能直接使用,要自己吸收並轉化成當前需要的內容。

好在這個功能並沒有太過複雜,直接使用就沒問題了。

基本資訊

裡面的答案有Swift2~4的寫法,不過實際測過之後Swift5能沿用Swift4的寫法,或許未來版本的Swift改了寫法也不用擔心,AI會幫你轉譯的。

程式碼

這邊我做了小小的改變,原文MBFormatter只寫死從抓來的rawData格式轉換成MB的方法,轉換GB顯示的直接使用原生的ByteCountFormatter,因此用ByteFormatter去靈活化返回的內容。

可能是Swift5的語法糖,只有一行的時候就不需要return關鍵字,會直接把這行返回的結果retrun回去。

import UIKit

extension UIDevice {
    //MARK: - formatter
    //彈性調整格式換算
    func ByteFormatter(_ bytes: Int64, units: ByteCountFormatter.Units, style: ByteCountFormatter.CountStyle = .decimal, incUnit: Bool = false) -> String {
        let formatter = ByteCountFormatter()
        formatter.allowedUnits = units
        formatter.countStyle = style
        formatter.includesUnit = incUnit
        return formatter.string(fromByteCount: bytes) as String
    }

    //MARK: - Get String Value
    //總儲存空間(GB)
    var totalDiskSpaceInGB:String { ByteFormatter(totalDiskSpaceInBytes, units: .useGB, incUnit: true) }
    //剩餘空間(GB)
    var freeDiskSpaceInGB:String { ByteFormatter(freeDiskSpaceInBytes, units: .useGB, incUnit: true) }
    //已使用空間(GB)
    var usedDiskSpaceInGB:String { ByteFormatter(usedDiskSpaceInBytes, units: .useGB, incUnit: true) }
    //總儲存空間(MB)
    var totalDiskSpaceInMB:String { ByteFormatter(totalDiskSpaceInBytes, units: .useMB) }
    //剩餘空間(MB)
    var freeDiskSpaceInMB:String { ByteFormatter(freeDiskSpaceInBytes, units: .useMB) }
    //已使用空間(MB)
    var usedDiskSpaceInMB:String { ByteFormatter(usedDiskSpaceInBytes, units: .useMB) }

    //MARK: - Get raw value
    //總儲存空間(Bytes)
    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
    }

    /*
     「重要」資源的可用總容量(以Bytes為單位),包含預計透過清除非必要與快取資源所釋放出的空間。「重要」是指使用者或應用程式明確希望保留在本機系統上,但最終仍可被替換的內容。這包括使用者透過 UI 明確要求的項目,以及應用程式為了提供功能所必需的資源。
     範例:使用者明確要求觀看但尚未看完的影片,或是使用者要求下載的音訊檔案。
     此數值不應用於判斷是否有足夠空間容納「不可替換」的資源。針對不可替換的資源,請一律嘗試儲存該資源,不管可用容量為何,並盡可能優雅地處理失敗情況。
     */
    var freeDiskSpaceInBytes:Int64 {
        if #available(iOS 11.0, *) {
            if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
                return space
            } 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
            }
        }
    }
    //已使用空間(Bytes)
    var usedDiskSpaceInBytes:Int64 { totalDiskSpaceInBytes - freeDiskSpaceInBytes }

}

使用方法:

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

結語

這其實不是什麼困難的功能,只是要用的時候就會忘記。

我觀察到的就是能從iOS那邊取出來的RawData就只有Bytes,還只有「全部空間」以及「剩餘空間」兩種,剩下的就是全靠計算與單位換算出來。

#swift