Сохранить изображения в NSUserDefaults? - PullRequest
75 голосов
/ 11 июля 2011

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

Ответы [ 12 ]

137 голосов
/ 11 июля 2011

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

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

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

NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
82 голосов
/ 16 февраля 2014

ВНИМАНИЕ!ЕСЛИ ВЫ РАБОТАЕТЕ ПОД 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 (см. Выделенную часть в пути: / var / mobile / Containers / Data / Application / B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1 / Documents / image.jpg).

Таким образом, есть 2 обходных пути:

  1. Пропустите эту проблему, так как после установки приложения на реальном устройстве этоникогда не изменяет UUID (на самом деле это так, но это новое приложение)
  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
}
27 голосов
/ 10 февраля 2015

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

8 голосов
/ 20 апреля 2018

Для 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)
    } 
}

чтобы установить изображение в качестве фона в настройках ВК Я использовал код ниже.

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")!
8 голосов
/ 01 апреля 2016

Для быстрой 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 голосов
/ 11 июля 2011

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

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

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

3 голосов
/ 16 мая 2017

Для 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)!
3 голосов
/ 13 февраля 2014

Из яблочной документации,

Класс NSUserDefaults предоставляет удобные методы для доступа к распространенным типам, таким как числа с плавающей запятой, двойные числа, целые числа, логические значения и 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];
2 голосов
/ 11 июля 2011

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

1 голос
/ 02 октября 2017

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

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

writeFile берет имя файла вашего изображения jpg (с расширением .jpg) и сам UIImage и возвращает true, если он можетsave или else возвращает 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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...