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?
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:
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
while allowed, is highly discouraged. Give each parameter a name, like in the following:
It will make your code a lot more descriptive.