Gytis Gytis - 16 days ago 5
iOS Question

How to improve user experience when loading a large UIImage?

I am using a large picture (2000x2000, 500kb) as a background image for most of the View Controllers in my iPad app.

The problem is that the app seems to freeze on the parent ViewController while loading the child ViewController with such an image for the first time (later it's faster due to caching I assume).

I would load it in a separate thread, and show some indicator while it's loading, however I know that all UI related operations should be done on the main thread.

Is there a way how I could improve the user experience, so the app does not seem to freeze for approx. 2sec? (tiling the image is not an option in my case)


It is wrong that all UIKit operations should be done on the main thread! Only operations that do drawing should be executed on the main thread. It is totally save to load a UIImage in a separate thread and hand it over to the main thread after that. However I don't think that the loading takes that long. I think this might be the drawing that takes the time.

But: As a UIActivityIndicatorView is running in it's own thread (as all CoreAnimation animations), it keeps animating, even if you block the main thread after the indicator is added. Try this:

UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[activityIndicator startAnimating];
[self addSubview:activityIndicator];

dispatch_async(dispatch_get_main_queue(), ^{
    UIImage* image = [UIImage imageNamed:@"MyImage"];
    UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
    [self addSubview:imageView];

    [activityIndicator removeFromSuperview];

This starts a UIActivityIndicator and begins loading the image in the next run loop cycle. After the image is added, it removes the superview. Maybe you have to dispatch the removal of the activity indicator again, so that UIKit has the time to draw the image. In this case, but the [activityIndicator removeFromSuperview] in another dispatch_async to the main queue within the first block.