Сохранить изображения в NSUserDefaults?


можно ли сохранить изображения в NSUserDefaults как объект, а затем извлечь для дальнейшего использования?

12 71

12 ответов:

внимание! Если вы работаете под iOS8 / XCODE6 см. мое обновление ниже

для тех, кто все еще ищет ответ Вот код "целесообразно" способ сохранить изображение в NSUserDefaults. Вы не должны сохранять данные изображения непосредственно в NSUserDefaults!

запись данных:

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

данные:

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

для iOS8 / XCODE6 Как tmr и DevC упоминалось в комментариях ниже есть проблема с xcode6 / ios8. Разница между процессом установки xcode5 и xcode 6 заключается в том, что xcode6 изменения приложений UUID после каждого запуска в xcode (см. highlighted часть в пути: /var / mobile / Containers / Data / Application/B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1/Документы/Изображения.формат JPG.)

Итак, есть 2 способа решения:

  1. пропустить эту проблему, как только приложение установлено на реальном устройстве это никогда не меняет UUID (на самом деле это так, но это новое приложение)
  2. сохранить относительный путь к нужной папке (в нашем случае к корню приложения)

вот swift версия кода в качестве бонуса (с 2-м подходом):

запись данных:

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()

данные:

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
}

чтобы сохранить изображение в NSUserDefaults:

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];

чтобы получить изображение из NSUserDefaults:

NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];

пока можно сохранить a UIImage до NSUserDefaults, это часто не рекомендуется, так как это не самый эффективный способ сохранения изображений; более эффективным способом является сохранение изображения в приложении Documents Directory.

для целей этого вопроса я приложил ответ на ваш вопрос, а также более эффективный способ сохранения UIImage.


NSUserDefaults (Не Рекомендуется)

сохранение в NSUserDefaults

этот метод позволяет сохранить любой UIImage до 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];
}

вот как вы это называете:

[self saveImageToUserDefaults:image ofType:@"jpg" forKey:@"myImage"];
[[NSUserDefaults standardUserDefaults] synchronize];

Загрузка Из NSUserDefaults

этот метод позволяет загружать любые UIImage С NSUserDefaults.

-(UIImage *)loadImageFromUserDefaultsForKey:(NSString *)key {
    NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
    return [UIImage imageWithData:[userDefaults objectForKey:key]];
}

вот как вы это называете:

UIImage * image = [self loadImageFromUserDefaultsForKey:@"myImage"];

Лучшая Альтернатива

сохранение документов Каталог

этот метод позволяет сохранить любой UIImage до Documents Directory в приложение.

-(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);
    }
}

вот как вы это называете:

NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:image withFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];

Загрузка Из Каталога Документов

этот метод позволяет загружать любые UIImage из приложения Documents Directory.

-(UIImage *)loadImageWithFileName:(NSString *)fileName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
    UIImage * result = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@.%@", directoryPath, fileName, [extension lowercaseString]]];

    return result;
}

вот как вы это называете:

NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:@"Ball" ofType:@"jpg" inDirectory:documentsDirectory];

Другой Альтернатива

сохранение UIImage в библиотеке фотографий

этот метод позволяет сохранить любой UIImage устройства Photo Library, и называется следующим образом:

UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

сохранение нескольких UIImages в библиотеку фотографий

этот метод позволяет сохранить несколько UIImages устройства 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);
    }
}

вот как вы это называете:

[self saveImagesToPhotoAlbums:images];

здесь images ваш NSArray в составе UIImages.

для swift 2.2

в магазине:

NSUserDefaults.standardUserDefaults().setObject(UIImagePNGRepresentation(chosenImage), forKey: kKeyImage)

для получения:

if let imageData = NSUserDefaults.standardUserDefaults().objectForKey(kKeyImage),
            let image = UIImage(data: imageData as! NSData){
            // use your image here...
}

Да , технически возможно, так как в

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:@"foo"];

но не рекомендуется, потому что plists не подходят для больших двоичных объектов данных, особенно пользовательских префов. Было бы лучше сохранить изображение в папку user docs и сохранить ссылку на этот объект в виде URL или пути.

Для Swift 4

я почти все перепробовал в этом вопросе, но никто не работал на меня. и я нашел свое решение. сначала я создал расширение для UserDefaults, как показано ниже, а затем просто вызвал get и 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)
    } 
}

чтобы установить изображение в качестве фона в settingsVC я использовал код ниже.

let croppedImage = cropImage(selectedImage, toRect: rect, viewWidth: self.view.bounds.size.width, viewHeight: self.view.bounds.size.width)

imageDefaults.setImage(image: croppedImage, forKey: "imageDefaults")

в mainVC :

let bgImage = imageDefaults.imageForKey(key: "imageDefaults")!

из документации apple,

класс NSUserDefaults предоставляет удобные методы для доступа к общим типам, таким как floats, Double, integers, Booleans и URL-адреса. Объект по умолчанию должен быть списком свойств, то есть экземпляром (или для коллекций комбинацией экземпляров): NSData, NSString, NSNumber, NSDate, NSArray или NSDictionary. Если вы хотите сохранить любой другой тип объекта, вы должны обычно архивировать его, чтобы создать экземпляр NSData.

Вы можете сохранить изображение такой:-

[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation([UIImage imageNamed:@"yourimage.gif"])forKey:@"key_for_your_image"];

и читать так: -

 NSData* imageData = [[NSUserDefaults standardUserDefaults]objectForKey:@"key_for_your_image"];
    UIImage* image = [UIImage imageWithData:imageData];

Это технически возможно, но не желательно. Вместо этого сохраните образ на диск. NSUserDefaults предназначен для небольших настроек, а не больших двоичных файлов данных.

на Swift 3 и JPG

Сохранить изображение в 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]];

загрузить изображение из 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]];

Да, вы можете использовать. Но так как это для хранения предпочтений, вы можете лучше сохранить изображения в папку с документами.

и вы можете иметь путь в NSUserDefaults, Если требуется.

поскольку этот вопрос имеет высокий индекс поиска google-вот ответ @NikitaTook в сегодняшнем дне и возрасте, т. е. Swift 3 и 4 (с обработкой исключений).

Примечание: этот класс написан исключительно для чтения и записи изображений формата JPG в файловую систему. Элемент Userdefaults вещи должны быть обработаны вне его.

writeFile принимает имя файла вашего jpg изображения (С.расширение jpg) и UIImage сам и возвращает true, если он может сохранить или же возвращает false если он не может записать изображение, в этот момент Вы можете сохранить изображение в Userdefaults который будет вашим планом резервного копирования или просто повторите еще раз. Элемент readFile функция принимает имя файла и возвращает UIImage, Если имя изображения, переданное этой функции, найдено, то оно возвращает это изображение, иначе оно просто возвращает изображение заполнителя по умолчанию из папки активов приложения (таким образом, вы можете избежать неприятных сбоев или другого странного поведения).

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