¿Guardar imágenes en NSUserDefaults?

Resuelto Florik asked hace 54 años • 13 respuestas

¿Es posible guardar imágenes NSUserDefaultscomo un objeto y luego recuperarlas para su uso posterior?

Florik avatar Jan 01 '70 08:01 Florik
Aceptado

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];
Bonny avatar Jul 11 '2011 10:07 Bonny

¡ATENCIÓN! SI ESTÁS TRABAJANDO BAJO 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" de guardar imágenes en NSUserDefaults. ¡NO DEBE guardar datos de imagen 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]];
}

ruta de documentos para nombre de archivo:

- (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 mencionaron 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/ imagen.jpg).

Entonces hay 2 soluciones:

  1. Evite ese problema, ya que una vez que la aplicación se instala en un dispositivo real, nunca cambia el UUID (de hecho, sí lo hace, pero es una aplicación nueva)
  2. 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 beneficio adicional (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)
}

ruta de documentos para nombre de archivo:

func documentsPathForFileName(name: String) -> String {
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true);
    let path = paths[0] as String;
    let fullPath = path.stringByAppendingPathComponent(name)

    return fullPath
}
Nikita Took avatar Feb 16 '2014 11:02 Nikita Took

Si bien es posible guardar un UIImagearchivo 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 la imagen en el archivo Documents Directory.

A los efectos de esta pregunta, adjunto la respuesta a su pregunta, junto con la forma más eficiente de guardar un archivo UIImage.


NSUserDefaults (no recomendado)

Guardar en NSUserDefaults

Este método le permite guardar cualquier UIImagearchivo en 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 UIImagearchivo 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 le permite guardar cualquiera UIImageen Documents Directoryla 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 UIImagearchivo desde el archivo 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];

Una alternativa diferente

Guardar UIImage en la biblioteca de fotos

Este método le permite guardar cualquiera UIImageen el archivo Photo Library, y se llama de la siguiente manera:

UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

Guardar múltiples UIImages en la biblioteca de fotos

Este método le permite guardar varios UIImagesen el archivo 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 imagesestá NSArraycompuesto UIImages?

Fernando Cervantes avatar Feb 10 '2015 02:02 Fernando Cervantes

Para rápido 4

Casi intenté todo en esta pregunta pero nadie funcionó para mí. y encontré mi solución. Primero creé una extensión para UserDefaults como se muestra a continuación, luego simplemente 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 principalVC:

let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!
Bilal Şimşek avatar Apr 19 '2018 22:04 Bilal Şimşek