Reputation: 706
I am facing performance issue with fetching and saving images in Core Data.
I have a Core Data entity that contains user's profile. Profile
includes one photo of the user and other details of him such as name, address etc.
For example, a row in the entity would look like as below.
Name, Address, Image, Details
If I remove the image, everything works fast. After adding image, each row takes around 1 ~ 5 seconds to be retrieved. The time lag depends on the size of the image that user uploaded (I verified time taken with and without image using Instruments).
I am storing the image as Transformable.
I tried fixing the issue by storing the image as binary data and using UIImagePNGRepresentation
. However, the issue became worser.
How to resolve this performance issue? I want to retain the image in Core Data itself due to the design of the app.
Upvotes: 1
Views: 1389
Reputation: 706
Finally I figured out a way... (thanks for all your suggestions).
This was my situation.
This is what I did
Below is the code to edit image. Set imagePicker.allowsEditing = YES
to show move and scale frame.
- (IBAction)myProfileImageEditButton:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.modalPresentationStyle = UIModalPresentationCurrentContext;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.delegate = self;
imagePicker.allowsEditing = YES;
[self presentViewController:imagePicker animated:YES completion:nil];
[self finishAndUpdateImage];
}
// This method is called when an image has been chosen from the library or taken from the camera.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//this line moves your original image into image.
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
//this line moves your original image into editedImage.
UIImage *editedImage = [info valueForKey:UIImagePickerControllerEditedImage];
//create an NSMutable array myImage and store both original and edited images for later use.
[self.myImages addObject:image];
[self.myImages addObject:editedImage];
[self dismissViewControllerAnimated:YES completion:NULL];
//declare your own updateImage method. Store both image and editedImage in core data (in my case, this is what I wanted. Change it based on your requirement). Retrieve only the smaller sized editedImage when user tries to view again.
[self updateImage];
}
Upvotes: 1
Reputation: 33428
Zaph answer is ok. If images are big you should save them in the file system and use Core Data only to save meta-informations about them.
A rule of thumb to decide how big images are can be found in the following discussion Core Data - Storing Images (iPhone). Marcus Zarra describes three main criteria to take the correct decision. Another important discussion can be found in Storing UIImage in Core Data with the new External Storage flag.
Starting from iOS 5, enabling external storage flag, Core Data heuristically decides on a per-value basis if it should save the data directly in the database or store a URI to a separate file which it manages for you. (Source Apple doc).
Based on that, what are the requirements for your app? Why do you need to maintain images in Core Data?
You should also think to maintain images in a separate entity but I really suggest to store them in the file system if this is possible. For example, using the external storage mechanism, performances would be optimized since Core Data manages this for you. I mean, Apple engineers did a lot of work under the hood. And so you can trust them. ;-)
Upvotes: 4
Reputation: 6011
In general, I agree with @Zaph.
Keep you images out of the CoreData persistent store if you can.
If you must store the image in CoreData, I would suggest to splice out the image
property from the Profile
entity and replace it with a relationship to a ProfileImage
entity (to-one).
This will allow you fetch Profile
objects without the overhead of loading the image data from disk without need.
Also, you will be able to do a background fetch (warm up the coordinator cache in background and only then access on main thread) of the image data if needed and reduce impact on user experience.
This will not help if you need to display the image along with the Profile
information on the same table view (for example) as the load time will be the same (use thumbs in this case).
You can still perform a background fetch of the images (async-load), but then you will have to manage memory consumption and not use the "great" functionality offered by the fetched results controller.
Upvotes: 0
Reputation: 112857
Best practice usually is to save the images in the app's documents directory (or sub directory) and the name of the image file in CoreData.
Upvotes: 1