Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A couple of thoughts:</p> <ol> <li><p>If you want to download 60 images, I would not advise using a serial queue for the download (e.g. do not use an operation queue with <code>maxConcurrentOperationCount</code> of <code>1</code>), but rather use a concurrent queue. You will want to synchronize the updates to make sure your code is thread-safe (and this is easily done by dispatching the updates to a serial queue, such as the main queue, for that final update of the model), but I wouldn't suggest using a serial queue for the download itself, as that will be much slower.</p></li> <li><p>If you want to use the <code>NSURLConnection</code> convenience methods, I'd suggest something like the following concurrent operation request approach (where, because it's on a background queue, I'm using <code>sendSynchronousRequest</code> rather than <code>sendAsynchronousRequest</code>), where I'll assume you have an <code>NSArray</code>, <code>imageURLs</code>, of <code>NSURL</code> objects for the URLs of your images:</p> <pre><code>NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 4; CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"all done %.1f", CFAbsoluteTimeGetCurrent() - start); NSLog(@"allImages=%@", self.allImages); }]; [imageURLs enumerateObjectsUsingBlock:^(NSURL *url, NSUInteger idx, BOOL *stop) { NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSURLResponse *response = nil; NSError *error = nil; NSData *data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] returningResponse:&amp;response error:&amp;error]; if (!data) { NSLog(@"%s sendSynchronousRequest error: %@", __FUNCTION__, error); } else { UIImage *image = [UIImage imageWithData:data]; if (image) { dispatch_sync(dispatch_get_main_queue(), ^{ [self.allImages replaceObjectAtIndex:idx withObject:image]; }); } } }]; [queue addOperation:operation]; [completionOperation addDependency:operation]; }]; [[NSOperationQueue mainQueue] addOperation:completionOperation]; </code></pre> <p>A couple of asides: First, I'm using an operation queue rather than a GCD concurrent queue, because it's important to be able to constrain the degree on concurrency. Second, I've added a completion operation, because I assume it would be useful to know when all the downloads are done, but if you don't need that, the code is obviously simper. Third, that benchmarking code using <code>CFAbsoluteTime</code> is unnecessary, but useful solely for diagnostic purposes if you want to compare the performance using a <code>maxConcurrentOperationCount</code> of <code>4</code> versus <code>1</code>.</p></li> <li><p>Better than using the <code>NSURLConnection</code> convenience methods, above, you might want to use a <code>NSOperation</code>-based network request. You can write your own, or better, use a proven solution, like <a href="https://github.com/AFNetworking/AFNetworking" rel="nofollow">AFNetworking</a>. That might look like:</p> <pre><code>CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"all done %.1f", CFAbsoluteTimeGetCurrent() - start); NSLog(@"allImages=%@", self.allImages); }]; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSerializer = [AFImageResponseSerializer serializer]; manager.operationQueue.maxConcurrentOperationCount = 4; [imageURLs enumerateObjectsUsingBlock:^(NSURL *url, NSUInteger idx, BOOL *stop) { NSOperation *operation = [manager GET:[url absoluteString] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { [self.allImages replaceObjectAtIndex:idx withObject:responseObject]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"%s image request error: %@", __FUNCTION__, error); }]; [completionOperation addDependency:operation]; }]; [[NSOperationQueue mainQueue] addOperation:completionOperation]; </code></pre> <p>Because AFNetworking dispatches those completion blocks back to the main queue, that solves the synchronization issues, while still enjoying the concurrent network requests.</p> <p>But the main take-home message here is that an <code>NSOperation</code>-based network request (or at least one that uses <code>NSURLConnectionDataDelegate</code>methods) opens additional opportunities (e.g. you can cancel all of those network requests if you have to, you can get progress updates, etc.).</p></li> <li><p>Frankly, having walked through two solutions that illustrate how to download the images efficiently up-front, I feel compelled to point out that this is an inherently inefficient process. I might suggest a "lazy" image loading process, that requests the images asynchronously as they're needed, in a just-in-time (a.k.a. "lazy") manner. The easiest solution for this is to use a <code>UIImageView</code> category, such as provided by <a href="https://github.com/AFNetworking/AFNetworking" rel="nofollow">AFNetworking</a> or <a href="https://github.com/rs/SDWebImage" rel="nofollow">SDWebImage</a>. (I'd use AFNetworking's if you're using AFNetworking already for other purposes, but I think that SDWebImage's <code>UIImageView</code> category is a little stronger.) These not only seamlessly load the images asynchronously, but offer a host of other advantages such as cacheing, more efficient memory usage, etc. And, it's as simple as:</p> <pre><code>[imageView setImageWithURL:url placeholder:[UIImage imageNamed:@"placeholder"]]; </code></pre></li> </ol> <p>Just a few thoughts on efficiently performing network requests. I hope that helps.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload