How to store an image in core data

I'm new to iOS. I've been trying to make an application that will store an image captured from the camera into CoreData. I now know how to store data like NSStrings, NSDate and other type but struggling to store an image. I've read so many articles saying you must write it to the disk and write to a file, but I can't seem to understand it.

The following code is the one i used to store other data to core data.

- (IBAction)submitReportButton:(id)sender
{
UrbanRangerAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];


managedObjectContext = [appDelegate managedObjectContext];


NSEntityDescription *entity = [NSEntityDescription entityForName:@"PotholesDB" inManagedObjectContext:appDelegate.managedObjectContext];
NSManagedObject *newPothole = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:managedObjectContext];




[newPothole setValue:self.relevantBody.text forKey:@"relevantBody"];
[newPothole setValue:self.subjectReport.text forKey:@"subjectReport"];
[newPothole setValue:self.detailReport.text forKey:@"detailReport"];
//    [newPothole setValue:self.imageView forKey:@"photo"];


NSDate *now = [NSDate date];
//NSLog(@"now : %@", now);
NSString *strDate = [[NSString alloc] initWithFormat:@"%@", now];
NSArray *arr = [strDate componentsSeparatedByString:@" "];
NSString *str;
str = [arr objectAtIndex:0];
NSLog(@"now : %@", str);


[newPothole setValue:now forKey:@"photoDate"];
[newPothole setValue:self.latitudeLabel.text forKey:@"latitude"];
[newPothole setValue:self.longitudeLabel.text forKey:@"longitude"];
[newPothole setValue:self.addressLabel.text forKey:@"streetName"];
[newPothole setValue:streeNameLocation forKey:@"location"];




NSError *error;
[managedObjectContext save:&error];


UIAlertView *ll = [[UIAlertView alloc] initWithTitle:@"Saving" message:@"Saved data" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];


[ll show];
}
85394 次浏览

I don't know why you want to store image in core data, while there is other persistent storage available in iOS. If you just want to store image for cache purpose, you can store it in document directory or cache directory. Happy Coding...

Please refer below URL, How to store and retrieve images in document directory.

http://www.wmdeveloper.com/2010/09/save-and-load-uiimage-in-documents.html

Saving image to Documents directory and retrieving for email attachment

How do I create a temporary file with Cocoa?

You can store images in Core Data using the Binary Data attribute type. However you should be aware of a few things:

  • Always convert your UIImage to a portable data format like png or jpg For example:

    NSData *imageData = UIImagePNGRepresentation(image);

  • Enable "Allows external storage" on this attribute description Core Data will move the data to an external file if it hits a certain threshold. This file is also completely managed by Core Data, so you don't have to worry about it.

  • If you run into performance issues, try moving the Binary Data attribute to a separate entity.

  • You should abstract the conversion to NSData behind the interface of your NSManagedObject subclass, so you don't have to worry about conversions from UIImage to NSData or vice versa.

  • If your images are not strongly related to the entities in your model, I would suggest storing them outside of Core Data.

- (void)imageChanged:(UIImage*)image{


if (self.detailItem) {
[self.detailItem setValue:UIImagePNGRepresentation(image) forKey:kSignatureImage];
}
}

In this a very brief example. self is a view controller using core data and self.detailItem is the usual NSManagedObject. In that project I did not create model classes for the entities but strictly use the KVC pattern to access the attributes. As you might guess, the attribute is named "signatureImage" which I had defined in an #define constant kSignatureImage.

This is where the image is restored from core data:

self.signatureCanvas.image =  [UIImage imageWithData:[self.detailItem valueForKey:kSignatureImage]];

Again, self is a view controller, signatureCanvas is a UIImageView subclass and .image is its regular image property inherited from UIImageView. detailItem, again, is the usual NSManagedObject.

The example is taken from a project I am currently working on.

There are pros and cons for storing large data objects like images in core data or having them separated in files. Storing them in files means that you are responsible for deleting them when the related data objects are deleted. That provides coding overhead and may be volatile for programming errors. On the other hand, it may slow down the underlying database. I have not yet enough experience with this approach that I could share with respect to performance. In the end, the disk storage occupied is about the same size in total.

In xcdatamodelId subclass declare image entity as NSData... you can't use UIImage format because image data is in binary format.

@property (nonatomic, retain) NSData *imag;

In Implementation file.. convert UIImage to NSData

UIImage *sampleimage = [UIImage imageNamed:@"sampleImage.jpg"];


NSData *dataImage = UIImageJPEGRepresentation(sampleimage, 0.0);

Then finally save it

[obj setValue:dataImage forKey:@"imageEntity"]; // obj refers to NSManagedObject

It is possible to store images in Core Data as UIImage. Although this is not considered to be good practice as Databases are not meant for storing files. We don't use core data to store the images directly instead we use the file path to where the image data is stored on your phone.

Anyways, the best method I found out while developing a side-project is demonstrated below

  1. Set the entity codeGen to Manual/None

  2. Select the attribute you want to be of Image type and choose transformable as it's type

  3. Enter Custom class identifier as UIImage

  4. Go to editor and select Create NSManagedObject Subclass

  5. The Process will create 2 swift files depending on the number of your entities(I only had 1 entity). Now, select the <EntityName> + CoreDataProperties.swift file and import UIKit

If, on clicking Jump to Definition for the @NSManaged public var UIImage definition your work is done.

Perform actions on the entities just like you would and you will be able to fetch, save, edit the image attribute by down-casting <EntityName>?.value(forKey: "<attributeName>") as? UIImage.

I had to use the entity as NSManagedObject type and was for some reason not able to access the image directly from the created subclass.

For Swift 5 and Swift 4.2

  1. convert UIImage to Data:

    let imageData = image.jpegData(compressionQuality: 1.0)
    
  2. save to CoreData:

    let object = MyEntity(context: managedContext)   //create object of type MyEntity
    object.image = imageData                         //add image to object
    
    
    do {
    try managedContext.save()                   //save object to CoreData
    } catch let error as NSError {
    print("\(error), \(error.userInfo)")
    }