Comment enregistrer des données locales dans une application Swift?

149

Je travaille actuellement sur une application iOS développée dans Swift et j'ai besoin de stocker du contenu créé par l'utilisateur sur l'appareil, mais je n'arrive pas à trouver un moyen simple et rapide de stocker / recevoir le contenu des utilisateurs sur l'appareil.

Quelqu'un pourrait-il expliquer comment stocker et accéder au stockage local?

L'idée est de stocker les données lorsque l'utilisateur exécute une action et de la recevoir au démarrage de l'application.

Nicklas Ridewing
la source
Salut et bienvenue, quel type de données stockez-vous? Pouvez-vous fournir un code pour donner un exemple de ce que vous recherchez? Merci.
Wez
1
Les données que je dois stocker sont essentiellement des données de chaîne. Donc, pour rester simple, je dois enregistrer deux valeurs String que je peux recevoir si l'utilisateur redémarre l'application.
Nicklas Ridewing
2
Vous pouvez utiliser NSUserDefaults. Voici les informations dont vous avez besoin codingexplorer.com/nsuserdefaults-a-swift-introduction
bpolat

Réponses:

197

La solution la plus simple si vous ne stockez que deux chaînes est NSUserDefaults, dans Swift 3, cette classe a été renommée juste UserDefaults.

Il est préférable de stocker vos clés quelque part dans le monde afin de pouvoir les réutiliser ailleurs dans votre code.

struct defaultsKeys {
    static let keyOne = "firstStringKey"
    static let keyTwo = "secondStringKey"
}

Swift 3.0, 4.0 et 5.0

// Setting

let defaults = UserDefaults.standard
defaults.set("Some String Value", forKey: defaultsKeys.keyOne)
defaults.set("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = UserDefaults.standard
if let stringOne = defaults.string(forKey: defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.string(forKey: defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Swift 2.0

// Setting

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Some String Value", forKey: defaultsKeys.keyOne)
defaults.setObject("Another String Value", forKey: defaultsKeys.keyTwo)

// Getting

let defaults = NSUserDefaults.standardUserDefaults()
if let stringOne = defaults.stringForKey(defaultsKeys.keyOne) {
    print(stringOne) // Some String Value
}
if let stringTwo = defaults.stringForKey(defaultsKeys.keyTwo) {
    print(stringTwo) // Another String Value
}

Pour tout ce qui est plus sérieux qu'une configuration mineure, des indicateurs ou des chaînes de base, vous devez utiliser une sorte de stockage persistant - Une option populaire pour le moment est Realm, mais vous pouvez également utiliser SQLite ou Apples très propres CoreData .

Wez
la source
7
Bel exemple. Cela devrait probablement être une énumération au lieu d'une structure.
pan-and-scan
3
C'est une étrange implémentation d'énumération, si vous n'avez que des constantes statiques, cela peut aussi bien être une structure.
Craig Grummitt
1
Ce code est faux. N'utilisez pas les méthodes KVC setValue(_:forKey:)pour enregistrer les données dans UserDefaults. Utilisez les UserDefaultsméthodes fournies de set(_:forKey:)(dans Swift 3).
rmaddy
J'ai mis à jour le code Swift 3. Je ne sais pas ce que devrait être la syntaxe Swift 2.
rmaddy
@rmaddy c'est bien tel quel.
Wez
57

Ils disent utiliser NSUserDefaults

Lorsque j'ai implémenté pour la première fois un stockage de données à long terme (après la fermeture de l'application), tout ce que j'ai lu en ligne m'a orienté vers NSUserDefaults. Cependant, je voulais stocker un dictionnaire et, bien que possible, cela se révélait pénible. J'ai passé des heures à essayer de faire disparaître les erreurs de type.

NSUserDefaults est également limité en fonction

Une lecture plus approfondie a révélé comment la lecture / écriture de NSUserDefaults oblige vraiment l'application à lire / écrire tout ou rien, en même temps, donc ce n'est pas efficace. Ensuite, j'ai appris que la récupération d'un tableau n'est pas simple. J'ai réalisé que si vous stockiez plus de quelques chaînes ou booléens, NSUserDefaults n'est vraiment pas idéal.

Ce n'est pas non plus évolutif. Si vous apprenez à coder, apprenez la méthode évolutive. N'utilisez NSUserDefaults que pour stocker des chaînes simples ou des booléens liés aux préférences. Stockez des tableaux et d'autres données à l'aide de Core Data, ce n'est pas aussi difficile qu'on le dit. Commencez petit.

Mise à jour: De plus, si vous ajoutez le support Apple Watch, il y a une autre considération potentielle. Les NSUserDefaults de votre application sont désormais automatiquement envoyés à l'extension Watch.

Utilisation des données de base

J'ai donc ignoré les avertissements selon lesquels Core Data était une solution plus difficile et j'ai commencé à lire. En trois heures, je l'ai fait fonctionner. Mon tableau de table était enregistré dans Core Data et rechargeait les données lors de l'ouverture de l'application de sauvegarde! Le code du didacticiel était assez facile à adapter et j'ai pu le faire stocker à la fois des tableaux de titres et de détails avec seulement un peu d'expérimentation supplémentaire.

Donc, pour tous ceux qui lisent cet article qui ont des problèmes de type NSUserDefault ou qui ont besoin de plus que de stocker des chaînes, envisagez de passer une heure ou deux à jouer avec les données de base.

Voici le tutoriel que j'ai lu:

http://www.raywenderlich.com/85578/first-core-data-app-using-swift

Si vous n'avez pas coché "Core Data"

Si vous n'avez pas coché "Core Data" lors de la création de votre application, vous pouvez l'ajouter après et cela ne prend que cinq minutes:

http://craig24.com/2014/12/how-to-add-core-data-to-an-existing-swift-project-in-xcode/

http://blog.zeityer.com/post/119012600864/adding-core-data-to-an-existing-swift-project

Comment supprimer des listes de données de base

Supprimer les données de Coredata Swift

Dave G
la source
6
Il existe un juste milieu pour enregistrer vos données dans un fichier .plist quelque part dans le répertoire Documents ou ailleurs dans le répertoire sandbox de l'application.
Nicolas Miari
Je suis novice, alors prenez cette question avec un grain de sel, mais est-ce un juste milieu? NSUserDefaults est pratiquement un fichier p.list de toute façon, donc (d'après ce que j'ai lu) enregistrer dans un fichier p.list dans le répertoire des documents revient à utiliser NSUserDefaults. La raison pour laquelle je n'ai pas utilisé cette méthode était parce que l'enregistrement d'un tableau dans une p.list semblait impliquer des étapes supplémentaires, comme le convertir en un autre type, puis plus tard, lors de la restauration des valeurs, il fallait réattribuer les valeurs après les avoir lues. de la p.list. Encore une fois, uniquement sur la base de ma lecture au cours des derniers jours.
Dave G
Eh bien, enregistrer un tableau dans un fichier .plist est assez simple (tous les objets de la hiérarchie sont des tableaux, des chaînes, des dictionnaires ou des nombres (pas de classes personnalisées).
Nicolas Miari
D'accord, la lecture du fichier est tout ou rien, mais vous pouvez diviser vos données en fichiers séparés en fonction de sa structure. Et CoreData a eu une courbe d'apprentissage significative, du moins la dernière fois que j'ai vérifié.
Nicolas Miari
3
Je dirais: utilisez NSUserDefaults pour stocker les préférences (c'est ce que le nom signifie après tout), le trousseau pour stocker des données persistantes et / ou sensibles, votre schéma personnalisé de fichiers .plist pour les données générées par des applications très basiques , et CoreData pour des choses plus lourdes .
Nicolas Miari
11

Merci donc à @bploat et au lien vers http://www.codingexplorer.com/nsuserdefaults-a-swift-introduction/

J'ai trouvé que la réponse est assez simple pour un stockage de chaînes de base.

let defaults = NSUserDefaults.standardUserDefaults()

// Store
defaults.setObject("theGreatestName", forKey: "username")

// Receive
if let name = defaults.stringForKey("username")
{
    print(name)
    // Will output "theGreatestName"
}

Je l'ai résumé ici http://ridewing.se/blog/save-local-data-in-swift/

Nicklas Ridewing
la source
9

L'utilisation de NSCoding et NSKeyedArchiver est une autre excellente option pour les données trop complexes NSUserDefaultspour lesquelles CoreData serait excessif. Cela vous donne également la possibilité de gérer la structure des fichiers plus explicitement, ce qui est idéal si vous souhaitez utiliser le cryptage.

Patrick Lynch
la source
7

Pour Swift 4.0, cela est devenu plus facile:

let defaults = UserDefaults.standard
//Set
defaults.set(passwordTextField.text, forKey: "Password")
//Get
let myPassword = defaults.string(forKey: "Password")
LevinsonTechnologies
la source
6

Swift 3.0

Setter: stockage local

let authtoken = "12345"
    // Userdefaults helps to store session data locally 
 let defaults = UserDefaults.standard                                           
defaults.set(authtoken, forKey: "authtoken")

 defaults.synchronize()

Obtention: stockage local

 if UserDefaults.standard.string(forKey: "authtoken") != nil {

//perform your task on success }
Ravindra Shekhawat
la source
2
Vous ne devriez pas enregistrer smth comme le authtoken dans UserDefaults..Veuillez utiliser le trousseau pour cela
BilalReffas
5

Pour Swift 3

UserDefaults.standard.setValue(token, forKey: "user_auth_token")
print("\(UserDefaults.standard.value(forKey: "user_auth_token")!)")
Arun Yokesh
la source
N'utilisez pas les méthodes KVC pour enregistrer les données.
rmaddy
4

Pour quelqu'un qui ne préférerait pas gérer UserDefaults pour certaines raisons, il existe une autre option - NSKeyedArchiver & NSKeyedUnarchiver. Il permet d'enregistrer des objets dans un fichier à l'aide de l'archiveur et de charger le fichier archivé dans les objets d'origine.

// To archive object,
let mutableData: NSMutableData = NSMutableData()
let archiver: NSKeyedArchiver = NSKeyedArchiver(forWritingWith: mutableData)
archiver.encode(object, forKey: key)
archiver.finishEncoding()
return mutableData.write(toFile: path, atomically: true)

// To unarchive objects,
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let object = unarchiver.decodeObject(forKey: key)
}

J'ai écrit un utilitaire simple pour enregistrer / charger des objets dans le stockage local, j'ai utilisé des exemples de codes ci-dessus. Vous voudrez peut-être voir ceci. https://github.com/DragonCherry/LocalStorage

DragonCerise
la source
4

Swift 5+

Aucune des réponses ne couvre vraiment en détail les capacités de stockage local intégrées par défaut. Il peut faire bien plus que de simples chaînes.

Vous avez les options suivantes directement à partir de la documentation Apple pour «obtenir» des données à partir des valeurs par défaut.

func object(forKey: String) -> Any?
//Returns the object associated with the specified key.

func url(forKey: String) -> URL?
//Returns the URL associated with the specified key.

func array(forKey: String) -> [Any]?
//Returns the array associated with the specified key.

func dictionary(forKey: String) -> [String : Any]?
//Returns the dictionary object associated with the specified key.

func string(forKey: String) -> String?
//Returns the string associated with the specified key.

func stringArray(forKey: String) -> [String]?
//Returns the array of strings associated with the specified key.

func data(forKey: String) -> Data?
//Returns the data object associated with the specified key.

func bool(forKey: String) -> Bool
//Returns the Boolean value associated with the specified key.

func integer(forKey: String) -> Int
//Returns the integer value associated with the specified key.

func float(forKey: String) -> Float
//Returns the float value associated with the specified key.

func double(forKey: String) -> Double
//Returns the double value associated with the specified key.

func dictionaryRepresentation() -> [String : Any]
//Returns a dictionary that contains a union of all key-value pairs in the domains in the search list.

Voici les options de 'réglage'

func set(Any?, forKey: String)
//Sets the value of the specified default key.

func set(Float, forKey: String)
//Sets the value of the specified default key to the specified float value.

func set(Double, forKey: String)
//Sets the value of the specified default key to the double value.

func set(Int, forKey: String)
//Sets the value of the specified default key to the specified integer value.

func set(Bool, forKey: String)
//Sets the value of the specified default key to the specified Boolean value.

func set(URL?, forKey: String)
//Sets the value of the specified default key to the specified URL.

Si vous stockez des éléments comme les préférences et non un grand ensemble de données , ce sont des options parfaitement adaptées.

Exemple double :

Réglage:

let defaults = UserDefaults.standard
var someDouble:Double = 0.5
defaults.set(someDouble, forKey: "someDouble")

Obtenir:

let defaults = UserDefaults.standard
var someDouble:Double = 0.0
someDouble = defaults.double(forKey: "someDouble")

Ce qui est intéressant à propos de l'un des getters, c'est dictionaryReprésentation , cet getter pratique prendra tous vos types de données quels qu'ils soient et les placera dans un joli dictionnaire auquel vous pouvez accéder par son nom de chaîne et donner le type de données correspondant correct lorsque vous demandez il revient car il est de type «any» .

Vous pouvez stocker vos propres classes et aussi des objets en utilisant le func set(Any?, forKey: String)etfunc object(forKey: String) -> Any? setter et getter en conséquence.

J'espère que cela clarifie davantage la puissance de la classe UserDefaults pour stocker des données locales.

Sur la note de combien vous devriez stocker et à quelle fréquence, Hardy_Germany a donné une bonne réponse à ce sujet sur ce post , en voici une citation

Comme beaucoup l'ont déjà mentionné: je ne connais aucune limitation de SIZE (sauf la mémoire physique) pour stocker des données dans un .plist (par exemple, UserDefaults). Ce n'est donc pas une question de COMBIEN.

La vraie question devrait être de savoir à quelle fréquence vous écrivez des valeurs nouvelles / modifiées ... Et cela est lié à l'épuisement de la batterie que cela entraînera.

IOS n'a aucune chance d'éviter une écriture physique sur "disque" si une seule valeur change, juste pour conserver l'intégrité des données. En ce qui concerne UserDefaults, tout le fichier est réécrit sur le disque.

Cela met le «disque» sous tension et le maintient sous tension plus longtemps et empêche l'IOS de passer à un état de faible consommation.

Quelque chose d'autre à noter comme mentionné par l'utilisateur Mohammad Reza Farahani à partir de ce message est la nature asynchrone et synchrone de userDefaults.

Lorsque vous définissez une valeur par défaut, elle est modifiée de manière synchrone au sein de votre processus et de manière asynchrone avec le stockage persistant et d'autres processus.

Par exemple, si vous enregistrez et fermez rapidement le programme, vous remarquerez peut-être qu'il n'enregistre pas les résultats, c'est parce qu'il persiste de manière asynchrone. Vous ne le remarquerez peut-être pas tout le temps, donc si vous prévoyez d'économiser avant de quitter le programme, vous voudrez peut-être en tenir compte en lui laissant le temps de terminer.

Peut-être que quelqu'un a quelques bonnes solutions pour cela qu'il peut partager dans les commentaires?

Joseph Astrahan
la source
0

NsUserDefaults enregistre uniquement de petites tailles variables. Si vous souhaitez enregistrer de nombreux objets, vous pouvez utiliser CoreData comme solution native, ou j'ai créé une bibliothèque qui vous aide à enregistrer des objets aussi facilement que la fonction .save (). Il est basé sur SQLite.

SundeedQLite

Découvrez-le et dites-moi vos commentaires

nour sandid
la source