How we increased the responsiveness of the application

Almost any modern application can not do without downloading pictures from the network and we, Surfingbird , are no exception. However, you cannot just upload images sequentially, because if the user rewinds a couple of screens, he will have to wait until the previous images are loaded, which are no longer needed.
Therefore, to increase the responsiveness of the application and reduce the user latency, we have applied several techniques that we want to talk about now.
It is worth noting that many use lazy loading pictures. This is a great practice, we love and respect it. This saves traffic and memory on the phone. However, in order to take care of memory, it is important not only to organize the competent storage of downloaded images, for example, crowding out the cache, but also to optimize the download itself.
Despite the fact that in the modern world users have long had unlimited Internet and traffic is not a problem, the latency for downloading images is still critical. The users are very impatient, they don’t want to wait for the download, they want to snort, and we give them this magic.
Take the case where an application is a collection of pictures. What will happen to a developer who does not think about the responsiveness of the application? He will take all the pictures, put them in the download queue and it turns out that they will be downloaded, on average, one after another.
See how it might look.
What do we see? The user has to wait for the previous images to load.
At the same time, the user does not see that something is happening at all. Now the application is slowing down for the user, and all because there is no way to understand whether the picture is loading or not.
It is important that the user has an understanding that everything is fine, everything is loading, a little more and a picture will appear. The first thing we did was add a progress bar to upload pictures. This is simple to implement: add a subview to our picture and change the progress of the callback:
// не надо относится к этому коду как к живому
// многие вещи типа логики показа/сокрытия progressView и тому подобные вещи скрыты
// код дан для того, чтобы было проще понять суть
-(void)layoutSubviews
{
CGRect rect = self.progressView.frame;
rect.size.width = self.bounds.size.width * self.progress;
self.progressView.frame = rect;
}
-(void)setProgress:(CGFloat)progress
{
_progress = progress;
if (_progress > 1)
_progress = 1;
if (_progress < 0)
_progress = 0;
[self setNeedsLayout];
}
And we prescribe downloadProgressBlock operations (for operations inherited from AFURLConnectionOperation):
[imageView.af_imageRequestOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
weakSelf.progress = totalBytesRead/totalBytesExpectedToRead;
}];
Here is what comes of it.
Despite the fact that the expectation of loading the picture is the same as in the first case, in the end, the user has the feeling that everything is fine.
But this is not at all ideal. As you can see from the example, if the user rewinds very far, then the wait for the image to load will be very long. So why not show primarily what is on the screen right now?
We use NSOperation to download each image. As soon as we get the next batch of content, we create a download operation for each picture and place it in the queue with medium priority. As soon as the picture is in sight, we set the operation to load it a high priority, and it is this picture that is loaded earlier than those that we do not need now.
There is one more subtlety - it is most likely that those pictures that the user scrolled are less needed than those that are below. Therefore, as soon as the picture disappears from the screen, we set the operation to load it even lower than the priority of the preload operations.
- (void) willAppear
{
[self.af_imageRequestOperation setQueuePriority:NSOperationQueuePriorityVeryHigh];
}
- (void) willDisappear
{
[self.af_imageRequestOperation setQueuePriority:NSOperationQueuePriorityVeryLow];
}

As a result, we were able to increase the responsiveness of the application and reduce the user latency. Visually, the application has become faster.
If you think that such tricks do not work, we recommend reading this Facebook research .
Do you use something like that? It will be nice to discuss in the comments.