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

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

Ответ 1

ВНИМАНИЕ! ЕСЛИ ВЫ РАБОТАЕТ ПОД 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 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 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 (см. Hightlighted part in path:/var/mobile/Containers/Data/Application/ B0D49CF5- 8FBE-4F14-87AE-FA8C16A678B1/Documents/image.jpg).

Итак, есть 2 способа обхода:

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

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

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

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
}

Ответ 2

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

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

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

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

Ответ 3

Хотя можно сохранить 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.

Ответ 4

Для быстрого 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...
}

Ответ 5

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

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

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

Ответ 6

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

Класс NSUserDefaults предоставляет удобные методы для доступа к общим типам, таким как float, doubleles, 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];

Ответ 7

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

Ответ 8

Для формата Swift 3 и JPG

Зарегистрировать изображение по умолчанию:

UserDefaults.standard.register(defaults: ["key":UIImageJPEGRepresentation(image, 100)!])

Сохранить изображение:

UserDefaults.standard.set(UIImageJPEGRepresentation(image, 100), forKey: "key")

Загрузить изображение:

let imageData = UserDefaults.standard.value(forKey: "key") as! Data
let imageFromData = UIImage(data: imageData)!

Ответ 9

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

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

Ответ 10

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

Ответ 11

Поскольку у этого вопроса есть высокий индекс поиска 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
    }
}