ios - programar - swift playgrounds iphone
Guardar imágenes en NSUserDefaults? (12)
¿Es posible guardar imágenes en NSUserDefaults
como un objeto y luego recuperarlas para un uso posterior?
Dado que esta pregunta tiene un alto índice de búsqueda de Google, aquí está la respuesta de @ NikitaTook en el día de hoy, es decir, Swift 3 y 4 (con manejo de excepciones).
Nota: Esta clase está escrita exclusivamente para leer y escribir imágenes de formato JPG en el sistema de archivos. Las cosas de Userdefaults
deben manejarse fuera de él.
writeFile
toma el nombre de archivo de su imagen jpg (con extensión .jpg) y el UIImage
mismo y devuelve true si es capaz de guardar o devuelve falso si no puede escribir la imagen, en ese momento puede almacenar la imagen en Userdefaults
que sería su plan de respaldo o simplemente Userdefaults
intentarlo una vez más. La función readFile
toma el nombre del archivo de imagen y devuelve un UIImage
, si se encuentra el nombre de la imagen transferido a esta función, devuelve esa imagen, sino que 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 otras conductas extrañas).
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
}
}
De la documentación de apple,
La clase NSUserDefaults proporciona métodos prácticos 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 lee así: -
NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"];
UIImage* image = [UIImage imageWithData:imageData];
Es técnicamente posible, pero no es aconsejable. Guarde la imagen en el disco en su lugar. 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]];
Para Swift 3 y formato JPG
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)!
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];
Sí, puedes usar Pero dado que es para almacenar las preferencias, puede guardar mejor las imágenes en la carpeta del documento.
Y puede tener la ruta en NSUserDefaults
, si es necesario.
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 Prefs de usuario. 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.
Si bien es posible guardar un UIImage
a 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 el Documents Directory
la aplicación.
A los fines de esta pregunta, adjunté la respuesta a su pregunta, junto con la forma más eficiente de guardar un UIImage
.
NSUserDefaults (No recomendado)
Guardar en NSUserDefaults
Este método le permite guardar cualquier UIImage
a 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 te permite cargar cualquier UIImage
desde 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"];
Una mejor alternativa
Guardar en el directorio de documentos
Este método te permite guardar cualquier UIImage
en el 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 UIImage
desde el Documents Directory
de la aplicación.
-(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];
Una alternativa diferente
Guardando UIImagel en la Biblioteca de fotos
Este método le permite guardar cualquier UIImage
a la Photo Library
del dispositivo y se llama de la siguiente manera:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
Guardar múltiples UIImages en Photo Library
Este método te permite guardar varios UIImages
en la Photo Library
del dispositivo.
-(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];
Where images
es tu NSArray
compuesto por UIImages
.
¡ATENCIÓN! SI TRABAJA BAJO iOS8 / XCODE6 VEA MI ACTUALIZACIÓN A CONTINUACIÓN
Para aquellos que aún 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 (vea parte destacada en la ruta: / var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg).
Entonces hay 2 soluciones:
- Omita ese problema, ya que una vez que la aplicación se instaló en el dispositivo real, nunca cambia el UUID (de hecho lo hace, pero es una nueva aplicación)
- Guarde la ruta relativa a la carpeta requerida (en nuestro caso a la raíz de la aplicación)
Aquí hay una versión rápida del código como una bonificación (con el 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 Swift 4
Casi lo intenté todo en esta pregunta, pero nadie se trabajó para mí. y encontré mi solución. primero, creé una extensión para UserDefaults como a continuación, y luego llamé a get y set methods.
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 establecer la imagen como fondo en settingsVC utilicé el código a continuación.
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 veloz 2.2
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...
}