1

I'm quite new to iOS programming. I've been working on a pretty simple camera app, but one major function I need to accomplish is to not only display an image taken with the built-in camera or picked from the iPhone gallery with a UIImageView, but also save it to the documents folder so it can be called in a second view controller later on. This I've managed to accomplish with the following code:

    //Save taken image to Camera Roll and display on UIImageView
    -(void)imagePickerController:(UIImagePickerController *)pickerdidFinishPickingMediaWithInfo:(NSDictionary *)info{

NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];

[self dismissModalViewControllerAnimated:YES];


if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {


    UIImage *image = [info 
                      objectForKey:UIImagePickerControllerOriginalImage];


    imageView.image = image;
    imageView.hidden = NO;

    if (newMedia)
        UIImageWriteToSavedPhotosAlbum(image, 
                                       self,
                                       @selector(image:finishedSavingWithError:contextInfo:),
                                       nil);
}
    //Save photo to documents folder
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:@"savedImage.png"];
UIImage *image = imageView.image; // imageView is my image from camera
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
}}

The problem I've run into is that the process of saving the image to the documents folder takes so long (>5sec!) that the user would think the app is hanging. Of course I want to display an activity indicator, but have now learned this isn't possible because the save to documents folder task is occupying my main thread, thus blocking any other UIView task from executing until saving is complete.

It seems like the solution is moving save to documents task to a background thread, but at the moment I can't quite wrap my head around how to do that. Does anyone know a some simple code I can add on to the above code to move this task to the background? Or maybe someone could refer me to a good tutorial on this?

EDIT:

Here's something else I've tried. I've set up @jake_hetfield 's saveImage method and placed just the save to documents code inside like so:

    - (void)saveImage:(UIImage*)image {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,        
    NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *savedImagePath = [documentsDirectory       
    stringByAppendingPathComponent:@"savedImage.png"];
    UIImage *image = imageView.image; // imageView is my image from camera
    NSData *imageData = UIImagePNGRepresentation(image);
    [imageData writeToFile:savedImagePath atomically:NO];

    [self performSelectorInBackground:@selector(saveImage:) withObject:image]; }

But the line UIImage *image = imageView.image; is suddenly returning the build error 'Redefinition of image'. This is confusing because that same line works when I ran the save to documents code in the PickerDidFinish... method. Any ideas of how I can fix this error?

Thanks in advance!

JR Lipartito
  • 11
  • 1
  • 3
  • You are redefining the variable image. You should remove the line UIImage *image = imageView.image; and instead send in your image as parameter of the method when you make the call OR remove the input parameter image of the method saveImage. You can't have two variables called image in the same method. See my edited answer. – jake_hetfield Aug 20 '12 at 08:58

1 Answers1

0

Create a method for saving an image and then call it using performSelectorInBackground, and it will be run in the background.

Example:

- (void)saveImage:(UIImage*)image{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    // Code for saving image here    

    [pool release];
}

Call it like this:

/* ... */

[self performSelectorInBackground:@selector(saveImage:) withObject:imageView.image];

/* ...*/
jake_hetfield
  • 3,388
  • 1
  • 23
  • 30
  • Thanks for your answer! But I'm still having trouble. I tried to add the saveImage method right before my code that saves to the docs folder (before NSArray *paths, etc). Somehow Xcode didn't like this, telling me that "saveImage" was undeclared. I could only get rid of that error by putting the saveImage method earlier, right before the PickerDidFinishPicking method, then calling it down at the bottom of my save to documents code. This builds&runs fine, but the saving task is still blocking my activity indicator from showing. Would you have an idea for what I'm doing wrong? – JR Lipartito Aug 17 '12 at 16:03
  • You have to declare the method in your header file (.h) within your class declaration and then you can add it anywhere you like in your class implementation in your .m-file. It sounds like you don't have the fundamental knowledge on how to create classes and methods in Objective-C. I suggest you practice the basics and learn the syntax a bit better before playing around with background tasks. – jake_hetfield Aug 20 '12 at 08:55
  • I change the answer slightly, I'm now sending in imageView.image as parameter – jake_hetfield Aug 20 '12 at 09:00