Сохранить изображения в NSUserDefaults?
Можно ли сохранить изображения в NSUserDefaults
как объект, а затем извлечь для дальнейшего использования?
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 (см. Выделенную часть в пути: / 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
}
Чтобы сохранить изображение в NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:UIImagePNGRepresentation(image) forKey:key];
Чтобы получить изображение из NSUserDefaults:
NSData* imageData = [[NSUserDefaults standardUserDefaults] objectForKey:key];
UIImage* image = [UIImage imageWithData:imageData];
Пока можно сохранить 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 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")!
Для быстрой 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"];
Но не рекомендуется, потому что списки не подходят для больших двоичных объектов двоичных данных, особенно для пользовательских настроек. Было бы лучше сохранить изображение в папке пользовательских документов и сохранить ссылку на этот объект в виде URL-адреса или пути.
Для формата 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)!
Это технически возможно, но не рекомендуется. Вместо этого сохраните изображение на диск. NSUserDefaults предназначен для небольших настроек, а не больших двоичных файлов данных.
Из яблочной документации,
Класс 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];
Да, вы можете использовать. Но так как это для хранения настроек, вы можете лучше сохранять изображения в папке документов.
И вы можете иметь путь в 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
}
}
Swift 4.x
Xcode 11.x
func saveImageInUserDefault(img:UIImage, key:String) {
UserDefaults.standard.set(img.pngData(), forKey: key)
}
func getImageFromUserDefault(key:String) -> UIImage? {
let imageData = UserDefaults.standard.object(forKey: key) as? Data
var image: UIImage? = nil
if let imageData = imageData {
image = UIImage(data: imageData)
}
return image
}
Сохранить изображение в 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]];