djibouti33
djibouti33

Reputation: 12132

AFNetworking: interrupt background requests for higher priority requests

Using AFNetworking, I need to download ~100 images in the background and store them to disk while ensuring any other network connectivity in my app takes precedence.

~~~~~~~

I've got an application that has 4 tabs. Each tab basically does the same thing: Pulls down a JSON response from a server, and displays a thumbnail grid of images, pulling down each image on demand (using AF's ImageView category). Tapping on a thumbnail takes you to a detail view controller where you see a larger image. The response and images are different for each tab.

There's a new requirement to fetch all of the images for the 4th tab ahead of time, so that theoretically by the time the user taps on the 4th tab, the JSON data and images are being read from disk.

I've got this working more or less right now, with the 4th tab pre-fetching and saving to disk being performed on a background thread so the main thread doesn't lock up. However, the network requests being kicked off when a user is on the 1st, 2nd or 3rd tab are being blocked by the pre-fetching network requests.

I'm using AFNetworking, and here is the code I'm using when Tab 1, 2 or 3 loads:

// this network request ends up getting blocked by the network request that
// is fired upon the application becoming active
- (void)getAllObjectDataWithBlock:(AFCompletionBlockWrapper)block
{
    [[[MyAPIClient] sharedClient] getPath:@"" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        block(operation, responseObject, nil);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        block(operation, nil, error);
    }];
}

And here is the code I'm using when my application becomes active, to pre-fetch content for the 4th tab:

// this network request runs in the background, but still blocks requests
// that should have a higher priority
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        NSOperationQueue *imageQueue = [[NSOperationQueue alloc] init];
        [imageQueue setMaxConcurrentOperationCount:8];

        for (NSString *imageURL in self.images) {                    
            NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL imageURL]];

            AFImageRequestOperation *operation = [[AFImageRequestOperation alloc] initWithRequest:request];
            [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
                NSLog(@"success");
            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                NSLog(@"fail");
            }];

            [imageQueue addOperation:smallOperation];
        }
    });
}

How can I structure things so any network requests kicked off from the main thread interrupt those that were kicked off in the background thread?

Upvotes: 3

Views: 3045

Answers (1)

Christopher Pickslay
Christopher Pickslay

Reputation: 17762

I don't know that you can easily interrupt running operations, unless you want to send them a cancel--but you'd have to look at whether AFImageRequestOperation pays attention to isCancelled.

Have you tried using setQueuePriority? You could start all the pre-fetching requests with a low priority, then add current tab requests with a higher priority. I believe running operations would complete, but once they complete, your higher-priority operations would get scheduled ahead of queued low-priority ones.

Upvotes: 3

Related Questions