Giuseppe Garassino
Giuseppe Garassino

Reputation: 2292

Quit app while for-loop is running

In my app I have a tableView filled with contents from a server. To download these contents I use NSURLConnection and I create a NSMutableArray (tableItems) to hold and to manage the addresses to the images I want to use.

In connectionDidFinishLoading, after populating tableItems, there is this for-loop:

for (int i = 0; i < [tableItems count]; i++) {

        // HERE I CHECK IF THE IMAGE I'M LOOKING FOR IS ALREADY ON DISK
        NSString *pathToCheckImage = [NSString stringWithFormat:@"%@/%@.png", pathToPreviews, [tableItems objectAtIndex:i]];
        NSData *dataOfCheckImage = [NSData dataWithContentsOfFile:pathToCheckImage];
        UIImage *checkImage = [UIImage imageWithData:dataOfCheckImage];

        NSString *pathToImage;
        UIImage *image;
        if (checkImage != nil) {
            // THE IMAGE IS ALREADY ON DISK SO I GET IT FROM TEMP FOLDER
            image = checkImage;
        } else {

            // THE IMAGE IS NEW SO I HAVE TO GET THE IMAGE FROM THE SERVER
            pathToImage = [NSString stringWithFormat:@"http://www.SERVER.com/SERVER_PATH/%@.png", [tableItems objectAtIndex:i]];

            NSURL *url = [NSURL URLWithString:pathToImage];
            NSData *data = [NSData dataWithContentsOfURL:url];
            image = [UIImage imageWithData:data];

            // AND SAVE IT ON DISK
            NSString *path = [NSString stringWithFormat:@"%@/%@.png", pathToPreviews, [tableItems objectAtIndex:i]];
            [self cacheImageOnDisk:image withPath:path];
        }

        if (image != nil) {
            [arrayOfImages addObject:image];
        }

}

This code is working, even if, depending on the number and size of the images I have to download from the server, it can take 1 or 2 minutes to perform its task.

The problem is that if the user quits (home button pushed) while this for-loop is running it keeps on performing its task until the end, even if it needs 1 minute to finish it.

During this period, launching the app again inevitably ends up crashing on startup.

I've tried to stop this for-loop on exit but applicationDidEnterBackground, applicationWillResignActive and applicationWillTerminate are not called until for-loop ends its task.

I've tried to set "application does not run in background", but nothing changed.

Any suggestion will be really appreciated.

Upvotes: 0

Views: 167

Answers (2)

Jason Harwig
Jason Harwig

Reputation: 45551

You should not be downloading images on the main thread. The app won't be responsive. Grand Central Dispatch is an easy method to accomplish these tasks.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSUInteger count = [tableItems count];
    for (int i = 0; i < count; i++) {
        // TODO: check if app didResignActive and break

        UIImage *image = ... // get image from disk or network

        // Add the image to the array on the main thread to avoid any threading issues
        dispatch_sync(dispatch_get_main_queue(), ^{
            [arrayOfImages addObject:image];
        });
    }
});

Upvotes: 4

Catfish_Man
Catfish_Man

Reputation: 41801

You need to either process your loop off the main thread (very easy to get wrong), or break your work into chunks (much simpler). Try extracting your loop into a separate method that runs it 10 times and then schedules another run with [... performSelector:@selector(myMethod) afterDelay:0]; That will give the runloop a chance to cycle and process events (like quit) every 10 iterations.

Threading (whether via older ways or the newer dispatch_async) will still get you better responsiveness though, so if you want to do that, my recommendation is this:

Share NO data between the background thread and the main thread while it's working.

Spawn your background thread, do your work entirely with local state not accessed anywhere else, then dispatch back to the main thread with your completed array. Any shared state is very likely to make your life very hard.

Upvotes: 1

Related Questions