web-dev-qa-db-fra.com

Enregistrer des images dans NSUserDefaults?

Est-il possible d'enregistrer des images dans NSUserDefaults en tant qu'objet, puis de les récupérer pour une utilisation ultérieure?

76
Florik

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:

  1. Ignorez ce problème, car une fois l'application installée sur un appareil réel, elle ne change jamais d'UUID (en fait, c'est le cas, mais c'est une nouvelle application)
  2. Enregistrer le chemin relatif dans le dossier requis (dans notre cas, à la racine de l'application)

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
}
82
Nikita Took

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];
137
Bonny

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.


NSUserDefaults (non recommandé)

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"];

Une meilleure alternative

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];

Une alternative différente

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];

images est votre NSArray composé de UIImages.

28
Fernando Cervantes

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")!
9
Bilal Şimşek

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...
}
8
alicanbatur

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.

5
Warren Burton

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];
3
Suraj K Thomas

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)!
3
Mc.Lover

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.

2
Benjamin Mayo

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
    }
}
1
Annjawn

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]];
1
Chetan Bhalara

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.

1
Ilanchezhian