Est-il possible d'enregistrer des images dans NSUserDefaults
en tant qu'objet, puis de les récupérer pour une utilisation ultérieure?
ATTENTION! SI VOUS TRAVAILLEZ SOUS iOS8/XCODE6, VOIR MA MISE À JOUR CI-DESSOUS
Pour ceux qui recherchent toujours une réponse, voici le code de la méthode "recommandée" pour enregistrer l'image dans NSUserDefaults. Vous NE DEVEZ PAS enregistrer les données d'image directement dans NSUserDefaults!
Écrire des données:
// Get image data. Here you can use UIImagePNGRepresentation if you need transparency
NSData *imageData = UIImageJPEGRepresentation(image, 1);
// Get image path in user's folder and store file with name image_CurrentTimestamp.jpg (see documentsPathForFileName below)
NSString *imagePath = [self documentsPathForFileName:[NSString stringWithFormat:@"image_%f.jpg", [NSDate timeIntervalSinceReferenceDate]]];
// Write image data to user's folder
[imageData writeToFile:imagePath atomically:YES];
// Store path in NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:imagePath forKey:kPLDefaultsAvatarUrl];
// Sync user defaults
[[NSUserDefaults standardUserDefaults] synchronize];
Lire les données:
NSString *imagePath = [[NSUserDefaults standardUserDefaults] objectForKey:kPLDefaultsAvatarUrl];
if (imagePath) {
self.avatarImageView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath]];
}
documentsPathForFileName:
- (NSString *)documentsPathForFileName:(NSString *)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
return [documentsPath stringByAppendingPathComponent:name];
}
Pour iOS8/XCODE6 Comme tmr et DevC mentionnés dans les commentaires ci-dessous, il y a un problème avec xcode6/ios8. La différence entre le processus d'installation de xcode5 et xcode 6 est que xcode6 change les UUID des applications après chaque exécution dans xcode (voir la partie en surbrillance dans le chemin:/var/mobile/Containers/Data/Application/B0D49CF5 -8FBE-4F14-87AE-FA8C16A678B1/Documents/image.jpg).
Il existe donc 2 solutions:
Voici Swift version du code en bonus (avec 2ème approche):
Écrire des données:
let imageData = UIImageJPEGRepresentation(image, 1)
let relativePath = "image_\(NSDate.timeIntervalSinceReferenceDate()).jpg"
let path = self.documentsPathForFileName(relativePath)
imageData.writeToFile(path, atomically: true)
NSUserDefaults.standardUserDefaults().setObject(relativePath, forKey: "path")
NSUserDefaults.standardUserDefaults().synchronize()
Lire les données:
let possibleOldImagePath = NSUserDefaults.standardUserDefaults().objectForKey("path") as String?
if let oldImagePath = possibleOldImagePath {
let oldFullPath = self.documentsPathForFileName(oldImagePath)
let oldImageData = NSData(contentsOfFile: oldFullPath)
// here is your saved image:
let oldImage = UIImage(data: oldImageData)
}
documentsPathForFileName:
func documentsPathForFileName(name: String) -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true);
let path = paths[0] as String;
let fullPath = path.stringByAppendingPathComponent(name)
return fullPath
}
Pour enregistrer une image dans NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
Pour récupérer une image à partir de NSUserDefaults:
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
Bien qu'il soit possible d'enregistrer un UIImage
dans NSUserDefaults
, il n'est souvent pas recommandé car ce n'est pas le moyen le plus efficace pour enregistrer des images; un moyen plus efficace consiste à enregistrer votre image dans le Documents Directory
.
Aux fins de cette question, j'ai joint la réponse à votre question, ainsi que le moyen plus efficace d'enregistrer un UIImage
.
Enregistrement dans NSUserDefaults
Cette méthode vous permet d'enregistrer tout UIImage
dans NSUserDefaults
.
-(void)saveImageToUserDefaults:(UIImage *)image ofType:(NSString *)extension forKey:(NSString *)key {
NSData * data;
if ([[extension lowercaseString] isEqualToString:@"png"]) {
data = UIImagePNGRepresentation(image);
} else if ([[extension lowercaseString] isEqualToString:@"jpg"]) {
data = UIImageJPEGRepresentation(image, 1.0);
}
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:data forKey:key];
[userDefaults synchronize];
}
Voici comment vous l'appelez:
[self saveImageToUserDefaults:image ofType:@"jpg" forKey:@"myImage"];
[[NSUserDefaults standardUserDefaults] synchronize];
Chargement à partir de NSUserDefaults
Cette méthode vous permet de charger n'importe quel UIImage
depuis NSUserDefaults
.
-(UIImage *)loadImageFromUserDefaultsForKey:(NSString *)key {
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
return [UIImage imageWithData:[userDefaults objectForKey:key]];
}
Voici comment vous l'appelez:
UIImage * image = [self loadImageFromUserDefaultsForKey:@"myImage"];
Enregistrement dans le répertoire des documents
Cette méthode vous permet d'enregistrer tout UIImage
dans le Documents Directory
dans l'application.
-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
if ([[extension lowercaseString] isEqualToString:@"png"]) {
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]] options:NSAtomicWrite error:nil];
} else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) {
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] options:NSAtomicWrite error:nil];
} else {
NSLog(@"Image Save Failed\nExtension: (%@) is not recognized, use (PNG/JPG)", extension);
}
}
Voici comment vous l'appelez:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:image withFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Chargement depuis le répertoire des documents
Cette méthode vous permet de charger n'importe quel UIImage
à partir du Documents Directory
.
-(UIImage *)loadImageWithFileName:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, [extension lowercaseString]]];
return result;
}
Voici comment vous l'appelez:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Enregistrement d'UIImage dans la photothèque
Cette méthode vous permet d'enregistrer tout UIImage
dans le Photo Library
, et est appelé comme suit:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
Enregistrement de plusieurs UIImages dans la photothèque
Cette méthode vous permet d'enregistrer plusieurs UIImages
dans le Photo Library
.
-(void)saveImagesToPhotoAlbums:(NSArray *)images {
for (int x = 0; x < [images count]; x++) {
UIImage * image = [images objectAtIndex:x];
if (image != nil) UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
}
Voici comment vous l'appelez:
[self saveImagesToPhotoAlbums:images];
Où images
est votre NSArray
composé de UIImages
.
Pour Swift 4
J'ai presque tout essayé dans cette question mais personne ne travaille pour moi. et j'ai trouvé ma solution. J'ai d'abord créé une extension pour UserDefaults comme ci-dessous, puis j'ai simplement appelé les méthodes get et set.
extension UserDefaults {
func imageForKey(key: String) -> UIImage? {
var image: UIImage?
if let imageData = data(forKey: key) {
image = NSKeyedUnarchiver.unarchiveObject(with: imageData) as? UIImage
}
return image
}
func setImage(image: UIImage?, forKey key: String) {
var imageData: NSData?
if let image = image {
imageData = NSKeyedArchiver.archivedData(withRootObject: image) as NSData?
}
set(imageData, forKey: key)
}
}
pour définir l'image comme arrière-plan dans settingsVC j'ai utilisé le code ci-dessous.
let croppedImage = cropImage(selectedImage, toRect: rect, viewWidth: self.view.bounds.size.width, viewHeight: self.view.bounds.size.width)
imageDefaults.setImage(image: croppedImage, forKey: "imageDefaults")
dans mainVC:
let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!
Pour Swift 2.2
Pour stocker:
NSUserDefaults.standardUserDefaults().setObject(UIImagePNGRepresentation(chosenImage), forKey: kKeyImage)
Pour récupérer:
if let imageData = NSUserDefaults.standardUserDefaults().objectForKey(kKeyImage),
let image = UIImage(data: imageData as! NSData){
// use your image here...
}
Oui, techniquement possible comme dans
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:@"foo"];
Mais ce n'est pas conseillé car les plists ne sont pas des endroits appropriés pour les gros blobs de données binaires, en particulier les User Prefs. Il serait préférable d'enregistrer l'image dans le dossier des documents utilisateur et de stocker la référence à cet objet sous forme d'URL ou de chemin.
Depuis Apple,
La classe NSUserDefaults fournit des méthodes pratiques pour accéder aux types courants tels que les flottants, les doubles, les entiers, les booléens et les URL. Un objet par défaut doit être une liste de propriétés, c'est-à-dire une instance de (ou pour les collections une combinaison d'instances de): NSData, NSString, NSNumber, NSDate, NSArray ou NSDictionary. Si vous souhaitez stocker tout autre type d'objet, vous devez généralement l'archiver pour créer une instance de NSData.
Vous pouvez enregistrer l'image comme ceci: -
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation([UIImage imageNamed:@"yourimage.gif"])forKey:@"key_for_your_image"];
Et lisez comme ceci: -
NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"];
UIImage* image = [UIImage imageWithData:imageData];
Pour le format Swift et JPG
Enregistrer l'image par défaut:
UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])
Enregistrer l'image:
UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")
Charger l'image:
let imageData = UserDefaults.standard.value(forKey: "key") as! Data
let imageFromData = UIImage(data: imageData)!
C'est techniquement possible, mais ce n'est pas conseillé. Enregistrez l'image sur le disque à la place. NSUserDefaults est destiné aux petits paramètres, pas aux gros fichiers de données binaires.
Puisque cette question a un index de recherche Google élevé - voici la réponse de @ NikitaTook dans la journée et l'âge d'aujourd'hui, c'est-à-dire Swift 3 et 4 (avec gestion des exceptions).
Remarque: Cette classe est uniquement écrite pour lire et écrire des images au format JPG dans le système de fichiers. Les éléments Userdefaults
doivent être gérés en dehors de celui-ci.
writeFile
prend le nom de fichier de votre image jpg (avec l'extension .jpg) et le UIImage
lui-même et retourne true s'il est capable d'enregistrer ou bien retourne false s'il est incapable d'écrire le image, à quel point vous pouvez stocker l'image dans Userdefaults
qui serait votre plan de sauvegarde ou simplement réessayer une fois de plus. La fonction readFile
prend le nom du fichier image et retourne un UIImage
, si le nom de l'image passé à cette fonction est trouvé alors il retourne cette image sinon il retourne juste une image d'espace réservé par défaut de l'application dossier de ressources (de cette façon, vous pouvez éviter les plantages désagréables ou d'autres comportements étranges).
import Foundation
import UIKit
class ReadWriteFileFS{
func writeFile(_ image: UIImage, _ imgName: String) -> Bool{
let imageData = UIImageJPEGRepresentation(image, 1)
let relativePath = imgName
let path = self.documentsPathForFileName(name: relativePath)
do {
try imageData?.write(to: path, options: .atomic)
} catch {
return false
}
return true
}
func readFile(_ name: String) -> UIImage{
let fullPath = self.documentsPathForFileName(name: name)
var image = UIImage()
if FileManager.default.fileExists(atPath: fullPath.path){
image = UIImage(contentsOfFile: fullPath.path)!
}else{
image = UIImage(named: "user")! //a default place holder image from apps asset folder
}
return image
}
}
extension ReadWriteFileFS{
func documentsPathForFileName(name: String) -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let path = paths[0]
let fullPath = path.appendingPathComponent(name)
return fullPath
}
}
Enregistrer l'image dans NSUserDefault:
NSData *imageData;
// create NSData-object from image
imageData = UIImagePNGRepresentation([dic objectForKey:[NSString stringWithFormat:@"%d",i]]);
// save NSData-object to UserDefaults
[[NSUserDefaults standardUserDefaults] setObject:imageData forKey:[NSString stringWithFormat:@"%d",i]];
Charger l'image à partir de NSUserDefault:
NSData *imageData;
// Load NSData-object from NSUserDefault
imageData = [[NSUserDefaults standardUserDefaults] valueForKey:[NSString stringWithFormat:@"%d",i]];
// get Image from NSData
[image setObject:[UIImage imageWithData:imageData] forKey:[NSString stringWithFormat:@"%d",i]];
Oui, vous pouvez utiliser. Mais comme c'est pour le stockage des préférences, vous pouvez mieux enregistrer les images dans le dossier du document.
Et vous pouvez avoir le chemin dans le NSUserDefaults
, si nécessaire.