Save Images in Nsuserdefaults

Save images in NSUserDefaults?

ATTENTION! IF YOU'RE WORKING UNDER iOS8/XCODE6 SEE MY UPDATE BELOW

For those who still looking for answer here is code of "advisable" way to save image in NSUserDefaults. You SHOULD NOT save image data directly into NSUserDefaults!

Write data:

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

Read data:

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

For iOS8/XCODE6
As tmr and DevC mentioned in comments below there is a problem with xcode6/ios8. The difference between xcode5 and xcode 6 installation process is that xcode6 changes apps UUID after each run in xcode (see hightlighted part in path: /var/mobile/Containers/Data/Application/B0D49CF5-8FBE-4F14-87AE-FA8C16A678B1/Documents/image.jpg).

So there are 2 workarounds:

  1. Skip that problem, as once app installed on real device it's never changes UUID (in fact it does, but it is new app)
  2. Save relative path to required folder (in our case to app's root)

Here is swift version of code as a bonus (with 2nd approach):

Write data:

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

Read data:

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
}

Error when trying to save image in NSUserDefaults using Swift

NSUserDefaults isn't just a big truck you can throw anything you want onto. It's a series of tubes which only specific types.

What you can save to NSUserDefaults:

  • NSData
  • NSString
  • NSNumber
  • NSDate
  • NSArray
  • NSDictionary

If you're trying to save anything else to NSUserDefaults, you typically need to archive it to an NSData object and store it (keeping in mind you'll have to unarchive it later when you need it back).


There are two ways to turn a UIImage object into data. There are functions for creating a PNG representation of the image or a JPEG representation of the image.

For the PNG:

let imageData = UIImagePNGRepresentation(yourImage)

For the JPEG:

let imageData = UIImageJPEGRepresentation(yourImage, 1.0)

where the second argument is a CGFloat representing the compression quality, with 0.0 being the lowest quality and 1.0 being the highest quality. Keep in mind that if you use JPEG, each time you compress and uncompress, if you're using anything but 1.0, you're going to degrade the quality over time. PNG is lossless so you won't degrade the image.

To get the image back out of the data object, there's an init method for UIImage to do this:

let yourImage = UIImage(data:imageData)

This method will work no matter how you converted the UIImage object to data.

In newer versions of Swift, the functions have been renamed, and reorganized, and are now invoked as:

For the PNG:

let imageData = yourImage.pngData()

For the JPEG:

let imageData = yourImage.jpegData(compressionQuality: 1.0)

Although Xcode will autocorrect the old versions for you

how to save UIImage to UserDefaults in swift 5

Try to use PropertyListEncoder() and Decoder like this:

func saveImage() {
guard let data = UIImage(named: "image").jpegData(compressionQuality: 0.5) else { return }
let encoded = try! PropertyListEncoder().encode(data)
UserDefaults.standard.set(encoded, forKey: "KEY")
}

func loadImage() {
guard let data = UserDefaults.standard.data(forKey: "KEY") else { return }
let decoded = try! PropertyListDecoder().decode(Data.self, from: data)
let image = UIImage(data: decoded)
}

Save UIImage array in NSUserDefaults

You can easily save your image in documentDirectory as below:

let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let fileURL = documentDirectory?.appendingPathComponent(yourImageName)

and then, you can give your image to UserDefaults

What's the disadvantage of saving image to NSUserDefault?

NSUserDefaults is explicitly meant for storing user defaults – images don't belong there especially because NSUserDefaults writes information into a .plist file. Raw image data does not belong into .plist files. Apart from that, it is also not very efficient: the more information you store in a .plist file, the longer it takes to load it. If you want to load a specific image, you would have to load the entire .plist file – including all the other images you don't need at the moment. Briefly speaking: don't do it.

A more appropriate and also more efficient approach for storing your images is to store them in your application's documents directory – where they belong to.

You could do that like this:

Storing your image

func saveImage(image: UIImage, fileName: String) {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let path = documentsURL?.appendingPathComponent(fileName)

do {
try UIImagePNGRepresentation(image)?.write(to: path!)
} catch {
// Handle possible errors here
print(error.localizedDescription)
}
}

Calling your saveImage function

let theImage = UIImage(named: "yourImage")
saveImage(image: theImage!, fileName: "yourImageName")

After storing your images to your application's documents directory, you could take your image's file path and store it in your CoreData database for retrieving the image later.

CoreData can also automate this for you with a little trick. By enabling the "Allows External Storage" checkbox for your binary data attribute, CoreData will store the image somewhere on your device and will only keep a reference to the image in your database (rather than the actual image), in order to keep the performance high. Here's some more information about that.

Changing UIImageView image and save it using NSUserDefaults

You can save the selected image in a couple of ways. One is to save the name of the image in the user defaults either when the view is exiting or when the image is changed by the user.

Here is how to save it when the user changes the image:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var backgroundImage: UIImageView!

let kBGImageNameKey = "bgImageName"

let lightBG = UIImage(named: "bg1.jpg")
let darkBG = UIImage(named: "bg2.jpg")

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

let defaults = NSUserDefaults.standardUserDefaults()
if let name = defaults.stringForKey(kBGImageNameKey) {
if (name == "bg1.jpg") {
backgroundImage.image = lightBG
} else {
backgroundImage.image = darkBG
}
}
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


@IBAction func changeBG(sender: AnyObject) {
let defaults = NSUserDefaults.standardUserDefaults()

if(backgroundImage.image == lightBG){
backgroundImage.image = darkBG
defaults.setObject("bg2.jpg", forKey: kBGImageNameKey)
}
else{
backgroundImage.image = lightBG
defaults.setObject("bg1.jpg", forKey: kBGImageNameKey)
}
}

}

This is just one way of doing this just to set you in the direction.



Related Topics



Leave a reply



Submit