Stop or completely erase iOS Global Dispatch Queue

260 views Asked by At

So I have read several posts on here about the queueing system but I cannot seem to figure out how to do what I am looking for. Currently I am going to a page and loading images using a loop, and each image uses async dispatch seen here.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
     //Load Image Code Goes Here
     dispatch_async(dispatch_get_main_queue(), ^{
          //Display Image Code Goes Here After Loading.
     });
});

And this works perfectly, however I need to be able to destroy this queue or wait until it is finished before doing anything else. Basically certain pages have dozens and dozens of images, so they all start loading, then I go to a totally separate area in the app and do a completely different image loading (1-2 images) and it will take almost a minute because it is still waiting for the other images to load. Is there a way to destroy my old queue or suspend? I have seen a people say "you can but it will corrupt the incoming data" which is fine because the image would just re download upon a new page load. Any ideas?

2

There are 2 answers

0
user3386109 On

A slightly different approach is to only dispatch a few images to start and then dispatch another when any of the previous requests finishes. Here's what the code looks like

- (IBAction)startButtonPressed
{
    self.nextImageNumber = 1;
    for ( int i = 0; i < 2; i++ )
        [self performSelectorOnMainThread:@selector(getImage) withObject:nil waitUntilDone:NO];
}

- (void)getImage
{
    if ( self.view.window && self.nextImageNumber <= 6 )
    {
        int n = self.nextImageNumber++;
        NSLog( @"Requesting image %d", n );

        NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://images.apple.com/v/iphone-5s/gallery/a/images/download/photo_%d.jpg", n]];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:url]];
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog( @"Received image %d", n );
                [self updateImage:image forView:n];
                [self performSelectorOnMainThread:@selector(getImage) withObject:nil waitUntilDone:NO];
            });
        });
    }
}

The images being downloaded are named "photo_1.jpg" through "photo_6.jpg". The process is started by requesting the first two photos. When one of those finishes, the next request is dispatched, and so on until all 6 photos are retrieved. The key line of code is

    if ( self.view.window && self.nextImageNumber <= 6 )

The first part of the if checks whether the view controller is still on the screen. When the user navigates away from the view controller, self.view.window will be set to nil. So navigating away from the view controller breaks the chain of downloads.

The second part of the if checks whether all of the downloads are finished. This is easy to do since the filenames contain a number. For random filenames, you could fill an NSArray with the URLs and then index through the array until you reach the end.

I started the chain with 2 downloads because there are only 6 images to download at that URL. Depending on the image sizes and number of images, you might want to start by dispatching more. The tradeoff is to maximize bandwidth usage (by starting with more) versus minimizing cancellation time (by starting with less).

3
Fonix On

if you are using an NSURLConnection, you should maybe keep references to them outside of the blocks, then if you move away from the screen call [downloadConnection cancel] on each of them