views:

90

answers:

3

Hi all -

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];
}
A: 

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
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
+2  A: 

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
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
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
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?
John N
Thanks for the update and clarification. It directly impacts something I'm working on.
John N
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
A: 

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
Tech - as mentioned, the delay is not nearly as noticeable on simulator. Please try it on the device and report your findings. Thanks!
Jim
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
What version of the SDK are you using?
Jim
It built under 3.1.3 which is what it was set for.
TechZen