1

I'm using AFNetworking to download more or less 200 images. The problem is that the main thread is blocked during the download, not during the success/failure block. Here is my code:

imageDownloads=[[NSMutableArray alloc]init];
for(NSString *url in liens){
    NSString *totalURL = [NSString stringWithFormat:@"http://%@", url];
    [imageDownloads addObject:[[ImageDownload alloc] initWithURL:[NSURL URLWithString:totalURL] filename:nil]];
}
for (int i=0; i < imageDownloads.count; i++)
{
    ImageDownload *imageDownload = imageDownloads[i];
    [self downloadImageFromURL:imageDownload];
}



   - (void)downloadImageFromURL:(ImageDownload *)imageDownload
{
    NSURLRequest *request = [NSURLRequest requestWithURL:imageDownload.url];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
        imageDownload.totalBytesRead = totalBytesRead;
        imageDownload.totalBytesExpected = totalBytesExpectedToRead;
        [self updateProgressView];
    }];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSAssert([responseObject isKindOfClass:[NSData class]], @"expected NSData");

        imageDownload.totalBytesExpected = imageDownload.totalBytesRead;
        [self updateProgressView];
        //all kind of basic stuff here I left out: I get store the data inside CoreData
        NSLog(@"finished %@", imageDownload);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"error %@", error);
    }];
    [operation start];
}

Basically, when I launch the code, the thread is blocked for like 30-40 seconds (the pictures are about 100MB in total), and then suddenly I can see all the NSLog logs appear with the "Finished"... text. So that part if really quick. But I thought AFNetworking wasn't supposed to block the main thread while I was downloading? This also doesn't allow me to track the progress of the download...Am I doing something wrong or misinterpreting something?

el-flor
  • 1,466
  • 3
  • 18
  • 39
  • Have you tried using dispatch_async? Then in the completion block you can return to the main thread. – brandonscript Sep 12 '15 at 16:57
  • I don't exactly understand at what point I'd have to use dispatch_async here? – el-flor Sep 12 '15 at 17:03
  • Build the entire request in an async block - just make sure that when your completion block calls any UI updates, that they're called on the main thread. See http://stackoverflow.com/a/16283719/1214800 – brandonscript Sep 12 '15 at 17:04
  • Look at this though: http://stackoverflow.com/questions/13133591/why-use-afnetworking-instead-of-dispatch-async The async should be included into AFNetworking... – el-flor Sep 12 '15 at 17:08
  • Added an answer to make it more clear – brandonscript Sep 12 '15 at 17:12

1 Answers1

0

You're updating the progress view in the progress block. Because AFNetworking is inherently async anyway, each of these requests will stack and run at the same time. If you're running 200 of them, that's going to freeze up the app. Try using NSOperationQueue's maxConcurrentOperationCount to limit the number of concurrent threads.

Alternatively, you could save all the trouble and just use .

brandonscript
  • 68,675
  • 32
  • 163
  • 220
  • Thanks a lot for your help. When I read this question though: http://stackoverflow.com/questions/13133591/why-use-afnetworking-instead-of-dispatch-async I seem to understand that AFNetworking in itself should be asynchronous already, right? – el-flor Sep 12 '15 at 17:13
  • Hrm good point. You're updating the progress UI in the progress block - how many of these are running simultaneously? – brandonscript Sep 12 '15 at 17:17
  • I've re-analyzed my code and here are my conclusions: the downloads are made asynchronously, but the problem is that as soon as one download finishes, it calls the success block (which is on the main thread), and so on, and so on (they all finish the one after the other). So the main thread remains blocked and that's why the progress isn't updated...What should I do? (there are more or less 150 pictures/blocks) – el-flor Sep 12 '15 at 17:25
  • I've seen it, but what do you think about my new comment? I think that's the main issue here ! – el-flor Sep 12 '15 at 17:26
  • You could also consider using something like SDWebImage, which will do all of this automagically – brandonscript Sep 12 '15 at 17:26
  • Well the problem is concurrent UI updates. You need to stagger those so they don't all happen at the same time. SDWebImage or maxConcurrent will help with that. – brandonscript Sep 12 '15 at 17:28
  • I will have a look at SDWebImage then. It also tracks progress during the downloads? – el-flor Sep 12 '15 at 17:29
  • I don't believe it does - I'd recommend using an activity indicator instead that doesn't require knowing the percent complete (only start and end). That said, if your images are big enough that you need a progress bar (e.g. several MB each) you should probably rethink downloading them simultaneously at all. – brandonscript Sep 12 '15 at 17:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89470/discussion-between-user3209448-and-remus). – el-flor Sep 12 '15 at 17:36