Long delay when saving image taken with camera or chosen from camera roll - iPhone
ios, iphone, objective-c, uiimagepickercontroller
Solution
Saving large images (like the ones taken by the camera in an iPhone 4/4S) takes a long time. If you profile the process, you'll find that `UIImagePNGRepresentation()` takes a while to generate your PNG image, but the primary bottleneck in my experience has been the writing to disk of a 1+ MB image.
There's little you can do to speed up this process aside from using JPEG compression, which I've found to be a little faster in my benchmarks, or using a faster third-party image compression routine. Therefore, if you don't want to block your user interface while this is happening, dispatch this saving process on a background thread or queue. You could do something like the following:
-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage* image = [info objectForKey: UIImagePickerControllerOriginalImage];
NSString* imageName = @"Receipt1Image1";
[self saveImage:image :imageName];
});
}
However, watch out for the fact that each of these UIImages use up quite a bit of memory to keep around, so you may want to use a dispatch semaphore to prevent more than one such image saving operation from occurring at the same time.
Also, as a stylistic note, defining an Objective-C method like
- (void)saveImage:(UIImage*)image:(NSString*)imageName
while allowed, is highly discouraged. Give each parameter a name, like in the following:
- (void)saveImage:(UIImage*)image fileName:(NSString*)imageName
It will make your code a lot more descriptive.
Problem
I am using the following code to allow a user of my application to take/choose a photo, which will then be saved to the documents directory and set as the image of a UIImageView: ``` -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { if (actionSheet.tag == 0){ if (buttonIndex == 0) { NSLog(@"Take Picture Button Clicked"); // Create image picker controller UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; // Set source to the camera imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; // Delegate is self imagePicker.delegate = self; // Show image picker [self presentModalViewController:imagePicker animated:YES]; } else if (buttonIndex == 1) { NSLog(@"Choose From Library Button Clicked"); // Create image picker controller UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; // Set source to the camera imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; // Delegate is self imagePicker.delegate = self; // Show image picker [self presentModalViewController:imagePicker animated:YES]; } else if (buttonIndex == 2) { NSLog(@"Cancel Button Clicked"); } } ...... - (void)saveImage:(UIImage*)image:(NSString*)imageName { NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format. NSFileManager *fileManager = [NSFileManager defaultManager];//create instance of NSFileManager NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image) receiptImageView1.image = [UIImage imageWithContentsOfFile:fullPath]; self.receiptImage1 = fullPath; NSLog(@"image saved"); } //Receive the image the user picks from the image picker controller -(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info { UIImage* image = [info objectForKey: UIImagePickerControllerOriginalImage]; NSString* imageName = @"Receipt1Image1"; [self saveImage:image :imageName]; } ``` Basically my problem is that this code seems to be executing very slowly, for example when I select an image from the camera roll it does eventually save and bring me back to the calling view, but only after a long delay.. Can anyone shed any light on this?