toma - Consulta el espacio en disco de iOS disponible con Swift
ios 11 ocupa mucho espacio (4)
Actualización de iOS 11
Las respuestas proporcionadas a continuación ya no proporcionan resultados precisos en iOS 11. Hay nuevas claves de capacidad de volumen que se pueden pasar a URL.resourceValues(forKeys:)
que proporcionan valores que coinciden con lo que está disponible en la configuración del dispositivo.
static let volumeAvailableCapacityKey: URLResourceKey
Clave para la capacidad disponible del volumen en bytes (solo lectura).static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey
Clave para la capacidad disponible del volumen en bytes para almacenar recursos importantes (solo lectura).static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey
Clave para la capacidad disponible del volumen en bytes para almacenar recursos no esenciales (solo lectura).static let volumeTotalCapacityKey: URLResourceKey
Clave para la capacidad total del volumen en bytes (solo lectura).
De la documentación de Apple :
Visión general
Antes de intentar almacenar una gran cantidad de datos localmente, primero verifique que tenga suficiente capacidad de almacenamiento. Para obtener la capacidad de almacenamiento de un volumen, construye una URL (utilizando una instancia de URL) que hace referencia a un objeto en el volumen a consultar, y luego consulta ese volumen.
Decidir qué tipo de consulta utilizar
El tipo de consulta a utilizar depende de lo que se almacena. Si está almacenando datos basados en una solicitud de usuario o recursos que la aplicación requiere para funcionar correctamente (por ejemplo, un video que el usuario está a punto de ver o los recursos que se necesitan para el siguiente nivel en un juego), consulte con
volumeAvailableCapacityForImportantUsageKey
. Sin embargo, si está descargando datos de una manera más predictiva (por ejemplo, descargando un episodio recientemente disponible de una serie de TV que el usuario ha estado viendo recientemente), consulte convolumeAvailableCapacityForOpportunisticUsageKey
.Construir una consulta
Use este ejemplo como una guía para construir su propia consulta:
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)")
}
Respuesta original
Encuadernación opcional con if let
funciona aquí.
Yo sugeriría que la función devuelva un Int64
opcional, de modo que pueda devolver nil
para indicar una falla:
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
}
Actualización 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
}
Actualización 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
}
Uso:
if let bytes = deviceRemainingFreeSpaceInBytes() {
print("free space: /(bytes)")
} else {
print("failed")
}
Estoy tratando de obtener el almacenamiento del dispositivo iOS disponible usando Swift
. Encontré esta función here
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
}
Pero en el momento de la compilación se da este error: [NSObject : AnyObject]? does not have a member named ''subscript''
[NSObject : AnyObject]? does not have a member named ''subscript''
Creo que este error surge del problema que se menciona here , a saber, que attributesOfFileSystemForPath
devuelve un diccionario opcional ( documentation ). Entiendo el problema en un sentido general, pero como la solución sugerida involucra un caso anidado, no veo cómo arreglar la función que me interesa (no ayuda que sea bastante nuevo en Swift
) . ¿Alguien puede sugerir cómo hacer que la función funcione? NOTA: No estoy seguro si la función original fue probada por el autor o si funcionó bajo una versión beta de xcode 6, pero no funciona bajo el GM por lo que puedo ver.
Bueno, de acuerdo a los códigos anteriores:
let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
puede que descubra que usedSpace no es igual al valor de la página de configuración del iPhone. Esto se debe a que en iOS11, Apple introduce la capacidad total disponible en bytes para los recursos "importantes" .
Capacidad total disponible en bytes para recursos "importantes", incluido el espacio que se espera que se elimine mediante la purga de recursos no esenciales y almacenados en caché. "Importante" significa algo que el usuario o la aplicación claramente espera que esté presente en el sistema local, pero que en última instancia es reemplazable. Esto incluiría los elementos que el usuario ha solicitado explícitamente a través de la interfaz de usuario y los recursos que requiere una aplicación para proporcionar funcionalidad.
Ejemplos: un video que el usuario solicitó explícitamente ver pero que aún no ha terminado de ver o un archivo de audio que el usuario solicitó descargar.
Este valor no debe utilizarse para determinar si hay espacio para un recurso insustituible. En el caso de recursos irremplazables, siempre intente guardar el recurso independientemente de la capacidad disponible y maneje las fallas con la mayor gracia posible.
Para obtener exactamente el mismo valor que vemos en la página de configuración de iPhone, podemos obtener espacio libre por volumenAvailableCapacityForImportantUsage
if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
return space ?? 0
}
Puedes usar la siguiente extensión de 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
}
}
uso:
Logger.d("totalDiskSpaceInBytes: /(UIDevice.current.totalDiskSpaceInBytes)")
Logger.d("freeDiskSpace: /(UIDevice.current.freeDiskSpaceInBytes)")
Logger.d("usedDiskSpace: /(UIDevice.current.usedDiskSpaceInBytes)")
Esto es similar a la respuesta de Martin para Swift 3.1 , pero se convierte en una extensión de UIDevice
para facilitar el acceso.
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
}
}
Para obtener espacio libre:
UIDevice.current.systemFreeSize
Y para obtener el espacio total:
UIDevice.current.systemSize
He escrito una clase para obtener memoria disponible / utilizada usando Swift. Demostración en: https://github.com/thanhcuong1990/swift-disk-status
Actualizar para soportar 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
}
}
}
Manifestación: