¿Es posible guardar imágenes NSUserDefaults
como un objeto y luego recuperarlas para su uso posterior?
Respuestas:
¡ATENCIÓN! SI ESTÁ TRABAJANDO CON iOS8 / XCODE6, VER MI ACTUALIZACIÓN A CONTINUACIÓN
Para aquellos que todavía buscan una respuesta, aquí hay un código de forma "recomendable" para guardar la imagen en NSUserDefaults. ¡NO DEBE guardar datos de imágenes directamente en NSUserDefaults!
Escribir datos:
// 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];
Leer datos:
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];
}
Para iOS8 / XCODE6 Como tmr y DevC se mencionan en los comentarios a continuación, hay un problema con xcode6 / ios8. La diferencia entre el proceso de instalación de xcode5 y xcode 6 es que xcode6 cambia el UUID de las aplicaciones después de cada ejecución en xcode (consulte la parte resaltada en la ruta: / var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg).
Entonces hay 2 soluciones alternativas:
Aquí hay una versión rápida del código como un bono (con un segundo enfoque):
Escribir datos:
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()
Leer datos:
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
}
Para guardar una imagen en NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
Para recuperar una imagen de NSUserDefaults:
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
Si bien es posible guardar un UIImage
en NSUserDefaults
, a menudo no se recomienda ya que no es la forma más eficiente de guardar imágenes; una forma más eficiente es guardar su imagen en la aplicación Documents Directory
.
A los efectos de esta pregunta, he adjuntado la respuesta a su pregunta, junto con la forma más eficiente de guardar un archivo UIImage
.
Guardar en NSUserDefaults
Este método le permite guardar cualquier UIImage
archivo 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];
}
Así es como lo llamas:
[self saveImageToUserDefaults:image ofType:@"jpg" forKey:@"myImage"];
[[NSUserDefaults standardUserDefaults] synchronize];
Cargando desde NSUserDefaults
Este método le permite cargar cualquier UIImage
archivo NSUserDefaults
.
-(UIImage *)loadImageFromUserDefaultsForKey:(NSString *)key {
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
return [UIImage imageWithData:[userDefaults objectForKey:key]];
}
Así es como lo llamas:
UIImage * image = [self loadImageFromUserDefaultsForKey:@"myImage"];
Guardar en el directorio de documentos
Este método le permite guardar cualquier UIImage
a la Documents Directory
dentro de la aplicación.
-(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);
}
}
Así es como lo llamas:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:image withFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Cargando desde el directorio de documentos
Este método le permite cargar cualquier archivo UIImage
de la aplicación Documents Directory
.
-(UIImage *)loadImageWithFileName:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, [extension lowercaseString]]];
return result;
}
Así es como lo llamas:
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];
Guardar UIImage en la biblioteca de fotos
Este método le permite guardar cualquiera UIImage
en el dispositivo Photo Library
y se llama de la siguiente manera:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
Guardar múltiples imágenes de UII en la biblioteca de fotos
Este método le permite guardar varios archivos UIImages
en el dispositivo 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);
}
}
Así es como lo llamas:
[self saveImagesToPhotoAlbums:images];
¿De dónde images
está tu NSArray
compuesto UIImages
?
inDirectory:(NSString *)directoryPath
? ¿Podrías llamarlo como quieras, como "myAppData"?
Para Swift 4
Casi probé todo en esta pregunta, pero nadie me funcionó. y encontré mi solución. Primero creé una extensión para UserDefaults como a continuación, luego llamé a los métodos get y 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)
}
}
para configurar la imagen como fondo en settingsVC utilicé el siguiente código.
let croppedImage = cropImage(selectedImage, toRect: rect, viewWidth: self.view.bounds.size.width, viewHeight: self.view.bounds.size.width)
imageDefaults.setImage(image: croppedImage, forKey: "imageDefaults")
en mainVC:
let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!
Para swift 2.2
Para almacenar:
NSUserDefaults.standardUserDefaults().setObject(UIImagePNGRepresentation(chosenImage), forKey: kKeyImage)
Para recuperar:
if let imageData = NSUserDefaults.standardUserDefaults().objectForKey(kKeyImage),
let image = UIImage(data: imageData as! NSData){
// use your image here...
}
Sí, técnicamente posible como en
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:@"foo"];
Pero no es aconsejable porque los plists no son lugares apropiados para grandes cantidades de datos binarios, especialmente User Prefs. Sería mejor guardar la imagen en la carpeta de documentos del usuario y almacenar la referencia a ese objeto como una URL o ruta.
Para Swift 3 y JPG formato
Registrar imagen predeterminada:
UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])
Guardar imagen :
UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")
Cargar imagen :
let imageData = UserDefaults.standard.value(forKey: "key") as! Data
let imageFromData = UIImage(data: imageData)!
De la documentación de Apple,
La clase NSUserDefaults proporciona métodos convenientes para acceder a tipos comunes como flotantes, dobles, enteros, booleanos y URL. Un objeto predeterminado debe ser una lista de propiedades, es decir, una instancia de (o para colecciones una combinación de instancias de): NSData, NSString, NSNumber, NSDate, NSArray o NSDictionary. Si desea almacenar cualquier otro tipo de objeto, normalmente debe archivarlo para crear una instancia de NSData.
Puede guardar una imagen como esta: -
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation([UIImage imageNamed:@"yourimage.gif"])forKey:@"key_for_your_image"];
Y lea así: -
NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"];
UIImage* image = [UIImage imageWithData:imageData];
Es técnicamente posible, pero no es recomendable. En su lugar, guarde la imagen en el disco. NSUserDefaults está diseñado para configuraciones pequeñas, no grandes archivos de datos binarios.
Guardar imagen en 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]];
Cargar imagen 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]];
Sí, puedes usar. Pero como es para el almacenamiento de preferencias, puede guardar mejor las imágenes en la carpeta de documentos.
Y puede tener la ruta en el NSUserDefaults
, si es necesario.
Dado que esta pregunta tiene un alto índice de búsqueda en Google, aquí está la respuesta de @ NikitaTook en la época actual, es decir, Swift 3 y 4 (con manejo de excepciones).
Nota: Esta clase está escrita únicamente para leer y escribir imágenes de formato JPG en el sistema de archivos. Las Userdefaults
cosas deben manipularse fuera de él.
writeFile
toma el nombre de archivo de su imagen jpg (con extensión .jpg) y el UIImage
mismo y devuelve verdadero si puede guardar o devuelve falso si no puede escribir la imagen, momento en el que puede almacenar la imagen en la Userdefaults
que sería su plan de respaldo o simplemente vuelva a intentarlo una vez más. La readFile
función toma el nombre del archivo de imagen y devuelve un UIImage
, si se encuentra el nombre de la imagen pasado a esta función, entonces devuelve esa imagen; de lo contrario, solo devuelve una imagen de marcador de posición predeterminada de la carpeta de activos de la aplicación (de esta manera puede evitar bloqueos desagradables u otros comportamientos extraños).
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
}
}
Swift 4.x
Xcode 11.x
func saveImageInUserDefault(img:UIImage, key:String) {
UserDefaults.standard.set(img.pngData(), forKey: key)
}
func getImageFromUserDefault(key:String) -> UIImage? {
let imageData = UserDefaults.standard.object(forKey: key) as? Data
var image: UIImage? = nil
if let imageData = imageData {
image = UIImage(data: imageData)
}
return image
}