1

I have been working with Apple's iPhone CoreDateRecipes sample code to learn more about tableviews and core data. I have coded my own test app based off of that sample, and it works well except for one thing. When I choose a photo for the 'recipe', no matter if it is from the camera or the library, when I hit "Done" to leave editing mode, it takes about 15 seconds before returning control to the user. This happens when testing on the device - in simulator, there is still a delay, but it is only 2-4 seconds.

I tested the "edit/done" button without choosing a photo and editing other data, and it saves instantaneously, so I'm pretty sure the image is to blame. Below is the code where it leaves editing mode, and the image processing code - what can I add/change/remove to speed this up? I know these sample code pieces are just proofs of concept, but I can't believe they published an example with such a crappy user experience!

Thanks, as always, for any guidance...let me know if there is any other code you need to see, or you can see the whole sample project here

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    [super setEditing:editing animated:animated];
    [self updatePhotoButton];

    nameTextField.enabled = editing;
    overviewTextField.enabled = editing;

    [self.navigationItem setHidesBackButton:editing animated:YES];


    if (!editing) {
        NSManagedObjectContext *context = recipe.managedObjectContext;
        NSError *error = nil;
        if (![context save:&error]) {
            NSLog(@"Error in RecipeDetailViewController:setEditing -- %@, %@",error, [error userInfo]);
            abort();
        }
    }
}


- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo {

    NSManagedObject *oldImage = recipe.image;
    if (oldImage != nil) {
        [recipe.managedObjectContext deleteObject:oldImage];
    }

    NSManagedObject *image = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:recipe.managedObjectContext];
    recipe.image = image;

    [image setValue:selectedImage forKey:@"image"];
    CGSize size = selectedImage.size;
    CGFloat ratio = 0;
    if (size.width > size.height) {
        ratio = 70.0 / size.width;
    } else {
        ratio = 70.0 / size.height;
    }

    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);

    UIGraphicsBeginImageContext(rect.size);
    [selectedImage drawInRect:rect];
    recipe.thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [self dismissModalViewControllerAnimated:YES];
}
Jim
  • 2,300
  • 1
  • 19
  • 43
  • Is the original code that slow or just after some modification? Can you add a link to the sample project? – Eiko Jun 23 '10 at 13:30
  • Eiko - the original code is that slow - I built the sample project with no modifications and was able to reproduce. Sorry, thought I had added a link - it is now added above – Jim Jun 23 '10 at 13:53
  • To replicate the issue - build the CoreDataRecipes app on device, then launch it and go into one of the recipes. Click the Edit button top right and then click on the recipe's picture at the top. This allows you to select a new photo from your library. Once the new pic is selected (which isn't that fast either!) click Done to save it - wait, wait, wait...Tried on both 3G and 3GS devices – Jim Jun 23 '10 at 13:56

3 Answers3

3

First, as Gilbert pointed out, example code is not meant for production use and will be slow.

Second, you should not store images in Core Data.  The example may show how to do it but it is generally a very bad idea.  You should be storing images on disk and then keeping a pointer (file path) to the image in Core Data.  There are some exceptions to this rule (very small images) but you should rethink your design.

Lastly, A lot of the slowness you are seeing may not be Core Data related.  The image picker code is very slow on its own.  I would recommend changing the code to just write to disk and see how slow that is compared to the writing to Core Data.  I would be surprised if it was much faster.

Update

You can store small images inside of Core Data and my advice from other posts stands, mores for the desktop than iOS.  The reason for this is the cache.  On iOS, the cache that Core Data uses is very small.  If you store images in the database that are large, you can blow out that cache easily and cause future calls that should be in the cache to hit the disk instead.  This is not a hard and fast rule of "don't store binary data" but more of a rule of watch your performance and if you are hitting the disk more than you should, binary data could easily be the cause.

Contacts

With regard to contacts, you can be slower because they are doing things differently than you are and they could easily be using private APIs to access the camera.  Because it is Apple, they don't necessarily play by the same rules as us.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • Second the slowness comment. Taking a picture on the iPhone 3G is *very* slow and there's nothing a developer can do about it. @Marcus, I feel like I asked you this before, but can you refresh my memory, why shouldn't you store images in core data? – kubi Jun 23 '10 at 17:32
  • Marcus - thanks for the informative post. I will experiment with saving to disk and seeing if the speed picks up. In regards to overall slowness - what about the Contacts application? It allows users to select or shoot photos to associate with contacts - shouldn't I at least be able to get comparable speed? – Jim Jun 23 '10 at 17:50
  • Marcus, is "you should not store images in Core Data" an update from your response here: http://stackoverflow.com/questions/2090028/core-data-storing-images-iphone, or do your rules in that answer still apply? – Cheddar Jun 23 '10 at 21:35
  • Thanks for the update and clarification. It directly impacts something I'm working on. – Cheddar Jun 24 '10 at 06:07
  • Well, I can say that moving the saving of the main image to disk was light night and day - I wonder if there is some other problem with Apple's code that made it that slow, since now (to disk) it is instantaneous. I am still saving thumbnails to core data, and that is fine - no delay at all. Thanks, Marcus!! – Jim Jun 25 '10 at 12:31
0

I'm not an iPhone developer, but generally, example code does not take into account the user experience. Example code shows examples.

In general, you need to perform expensive (long running) operations in additional threads.

Maybe this blog post will help: Respect the Main Thread

Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • Thanks for the link, I'm not really in need of threading in this app (yet) but it is good to know what my options are. – Jim Jun 25 '10 at 12:31
0

I downloaded the project, built it and ran it in the simulator. I couldn't reproduce your problem. I found that the time it took to save an image was visually instantaneous i.e. no longer than the view transition.

If you see the same issue on the original, unmodified project, then you have something else going on. Make sure you have the latest version of the project which should be the one at your link. I know there is at least one really old one floating around because I hit it recently.

TechZen
  • 64,370
  • 15
  • 118
  • 145
  • Tech - as mentioned, the delay is not nearly as noticeable on simulator. Please try it on the device and report your findings. Thanks! – Jim Jun 25 '10 at 12:32
  • You said there was a 2-4 second delay on your simulator. I experienced zero delay. The views transitioned perfectly smoothly. I'll see if I can test on device but I don't expect to see anything. – TechZen Jun 25 '10 at 12:44
  • What version of the SDK are you using? – Jim Jun 25 '10 at 19:45
  • It built under 3.1.3 which is what it was set for. – TechZen Jun 25 '10 at 20:47