How to store an image in core data
IosObjective CCore DataIos Problem Overview
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 NSString
s, 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];
}
Ios Solutions
Solution 1 - Ios
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][1] [1]: http://i.stack.imgur.com/6yRWE.png 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.
Solution 2 - Ios
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
Solution 3 - Ios
For Swift 5 and Swift 4.2
-
convert
UIImage
toData
:let imageData = image.jpegData(compressionQuality: 1.0)
-
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)") }
Solution 4 - Ios
- (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.
Solution 5 - Ios
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
-
Select the attribute you want to be of Image type and choose transformable as it's type
-
Go to editor and select Create NSManagedObject Subclass
-
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.
Solution 6 - Ios
Few links which might help you to get through this
https://stackoverflow.com/a/3909082/558000
https://stackoverflow.com/questions/3353172/save-and-retrieve-of-an-uiimage-on-coredata
Solution 7 - Ios
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</strike>
https://stackoverflow.com/questions/215820/how-do-i-create-a-temporary-file-with-cocoa