在 NSUserDefault 中保存图像?

是否有可能将图像作为对象保存到 NSUserDefaults中,然后进行检索以供进一步使用?

66992 次浏览

在 NSUserDefault 中保存图像:

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

要从 NSUserDefault 检索图像:

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

是的,您可以使用。但是由于它是用来存储首选项的,所以您可以更好地将图像保存到文档文件夹中。

如果需要,您可以在 NSUserDefaults中获得路径。

是的,技术上可行

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

但是不建议这样做,因为 plist 不适合放置大量二进制数据,尤其是 User Prefs。最好将图像保存到用户文档文件夹,并将对该对象的引用存储为 URL 或路径。

将图像保存到 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]];

技术上可行,但不可取。而是将映像保存到磁盘。NSUserDefault 用于小的设置,而不是大的二进制数据文件。

从苹果的文档中,

NSUserDefault 类提供了访问浮点数、双精度数、整数、布尔值和 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];

注意! 如果你在 iOS8/XCODE6下工作,请看下面我的更新

对于那些仍然在这里寻找答案的人来说,这里是用 NSUserDefault 保存图像的“明智”方法的代码。您不应该将图像数据直接保存到 NSUserDefault!

写入数据:

// 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 正如 tmrandDevC 在下面的评论中提到的,xcode6/ios8有一个问题。Xcode5和 xcode 6安装过程的不同之处在于,xcode6 更改应用程序 UUID在每次运行 xcode 之后(参见路径:/var/mobile/Container/Data/Application/B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1/Document/image. jpg 中突出显示的部分)。

因此,有两种解决办法:

  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
}

虽然将 UIImage保存到 NSUserDefaults是可能的,但通常不推荐这样做,因为这不是保存图像的最有效方法; 更有效的方法是将图像保存到应用程序的 Documents Directory中。

对于这个问题,我已经附上了你的问题的答案,随着更有效的方式保存 UIImage


NSUserDefault (不推荐)

保存为 NSUserDefault

此方法允许您将任何 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];

从 NSUserDefault 加载

此方法允许您从 NSUserDefaults加载任何 UIImage

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

从文档目录加载

此方法允许您从应用程序的 Documents Directory加载任何 UIImage

-(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是由 UIImages组成的 NSArray

快速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...
}

适用于 Swift 3JPG格式

注册表默认值图片来源:

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

由于这个问题有很高的谷歌搜索索引-这里是@NikitaTake 在今天的答案,也就是 Swift 3和4(除了处理异常)。

注意: 此类仅用于向文件系统读写 JPG 格式的图像。Userdefaults的东西应该在外面处理。

writeFile接受 jpg 映像的文件名(使用。如果能够保存,返回 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

在这个问题上我几乎尝试了所有的方法,但是没有人为我工作。我找到了我的解决办法。 首先,我为 UserDefault 创建了一个扩展,如下所示,然后调用 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")!

斯威夫特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
}