J'essaie d'obtenir le stockage de périphérique iOS disponible à l'aide de Swift
. J'ai trouvé cette fonction ici
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
}
Mais au moment de la compilation, cette erreur est donnée: [NSObject : AnyObject]? does not have a member named 'subscript'
Je crois que cette erreur provient du problème mentionné ici , à savoir que attributesOfFileSystemForPath
renvoie un dictionnaire optionnel ( documentation ). Je comprends le problème dans son sens général, mais comme la solution proposée implique un cas imbriqué, je ne vois pas trop comment résoudre le problème qui m’intéresse (cela ne aide en rien que je sois assez nouveau pour Swift
) . Quelqu'un peut-il suggérer comment faire fonctionner la fonction? NOTE: Je ne suis pas sûr si la fonction originale a été testée par l'auteur ou si elle a fonctionné sous une version bêta de xcode 6, mais cela ne fonctionne pas sous le GM à ma connaissance.
Les réponses données ci-dessous ne fournissent plus de résultats précis sous iOS 11. De nouvelles clés de capacité de volume pouvant être passées à URL.resourceValues(forKeys:)
fournissent des valeurs correspondant à celles disponibles dans les paramètres du périphérique.
static let volumeAvailableCapacityKey: URLResourceKey
Clé de la capacité disponible du volume en octets (en lecture seule).
static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey
Clé de la capacité disponible du volume en octets pour le stockage des ressources importantes (en lecture seule).
static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey
Clé de la capacité disponible du volume en octets pour le stockage des ressources non essentielles (en lecture seule).
static let volumeTotalCapacityKey: URLResourceKey
Clé de la capacité totale du volume en octets (lecture seule).
De Documentation Apple :
Vue d'ensemble
Avant d'essayer de stocker localement une grande quantité de données, vérifiez d'abord que vous avez une capacité de stockage suffisante. Pour obtenir la capacité de stockage d'un volume, vous construisez une URL (à l'aide d'une instance d'URL) qui référence un objet sur le volume à interroger, puis interrogez ce volume.
Décider du type de requête à utiliser
Le type de requête à utiliser dépend de ce qui est stocké. Si vous stockez des données basées sur une requête utilisateur ou sur des ressources indispensables à l'application pour fonctionner correctement (par exemple, une vidéo que l'utilisateur est sur le point de regarder ou des ressources nécessaires pour le niveau suivant d'un jeu), lancez une requête sur
volumeAvailableCapacityForImportantUsageKey
. Toutefois, si vous téléchargez des données de manière plus prédictive (par exemple, le téléchargement d’un épisode d’une série télévisée récemment disponible que l’utilisateur a regardé récemment), effectuez une requête survolumeAvailableCapacityForOpportunisticUsageKey
.Construire une requête
Utilisez cet exemple comme guide pour construire votre propre requête:
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)")
}
Liaison facultative avec if let
fonctionne également ici.
Je suggérerais que la fonction retourne un Int64
optionnel, de sorte qu'elle puisse renvoyer nil
pour signaler un échec:
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
}
Mise à jour 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
}
Mise à jour 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")
}
J'ai écrit un cours pour obtenir de la mémoire disponible/utilisée avec Swift. Démo sur: https://github.com/thanhcuong1990/Swift-disk-status
Mise à niveau pour prendre en charge 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
}
}
}
Démo:
Eh bien, selon les codes ci-dessus:
let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
vous découvrirez peut-être que usedSpace ne correspond pas à la valeur de la page de configuration de l'iPhone. En effet, dans iOS11, Apple introduit Capacité totale disponible en octets pour les ressources "Important" .
Capacité totale disponible en octets pour les ressources "Important", y compris Espaces devant être libérés en purgeant les ressources non essentielles et mises en cache . "Important" signifie quelque chose que l'utilisateur ou l'application S'attend clairement à voir être présent sur le système local, mais qu'il est finalement Remplaçable. Cela comprend les éléments que A explicitement demandés à l'utilisateur via l'interface utilisateur, ainsi que les ressources nécessaires à une application afin de fournir des fonctionnalités.
Exemples: Une vidéo que l'utilisateur A explicitement demandé à visionner mais n'a pas encore fini de regarder ou Un fichier audio que l'utilisateur a demandé de télécharger.
Cette valeur Ne doit pas être utilisée pour déterminer s’il reste de la place pour une ressource Irremplaçable. Dans le cas de ressources irremplaçables, tentez toujours de sauvegarder la ressource, quelle que soit la capacité disponible, et Gérerez les pannes de la manière la plus élégante possible.
Pour obtenir exactement la même valeur que ce que nous voyons dans la page de configuration de l'iPhone, nous pouvons obtenir de l'espace libre avec volumeAvailableCapacityForImportantUsage
if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage {
return space ?? 0
}
Vous pouvez utiliser l’extension UIDevice suivante :
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)")
Ceci est similaire à la réponse de Martin pour Swift 3.1 , mais est converti en une extension de UIDevice
pour en faciliter l'accès.
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
}
}
Pour obtenir de l'espace libre:
UIDevice.current.systemFreeSize
Et pour obtenir un espace total:
UIDevice.current.systemSize