1. What is the demand point?
The multi-image download Here is to display a picture in every cell in TableView, and these images need to be downloaded from the Internet.
2. Easy-to-encounter problems
If you do not know or use asynchronous operations and caching mechanisms, it is likely that the code is written like this:
Cell.textLabel.text = App.name;cell.detailtextlabel.text = App.download;
NSData *imagedata = [NSData datawithcontentsofurl:app.url];cell.imageview.image = [UIImage imagewithdata:imagedata];
What is the consequence of this writing?
Consequence 1: unavoidable lag (because there is no asynchronous download operation)
Datawithcontentsofurl: is a time-consuming operation, placing it on the main thread will cause the Dayton. If the picture is many, the picture is very big, and the network condition is not good, certainly will be stuck!
Consequence 2: Duplicate download of the same picture, consuming traffic and overhead (because no caching mechanism is established)
Because there is no caching mechanism, even though the download is complete and the current cell's picture is displayed, the cell will download its corresponding picture when it needs to be displayed again: it consumes download traffic and causes repeated operations.
Obviously, to achieve tableview rolling, such as silky-like enjoyment must be both, how to do it?
3. Solution
1. First look at the flowchart of the solution
To get a quick look at this diagram, you need to understand all the data sources that the process requires:
1. URL of the picture: Because each image corresponds to the URL is unique, so we can create the image cache and download operation of the cache key, as well as stitching the path string of the sandbox cache.
2. Picture cache (Dictionary): stored in memory, key is the URL of the picture, the value is UIImage object. Function: Fast reading speed, direct use of UIImage object.
3. Download operation cache (dictionary): Store with memory, key is the URL of the picture, the value is Nsblockoperation object. Role: To avoid opening multiple download threads for the same picture.
4. Sandbox cache (file path corresponds to NSData): stored on disk, located in the Cache folder, the path is "cache/the last part of picture url", the value is NSData object (convert UIImage to NSData to write to disk). Function: The program breaks the net, start again can also get the picture directly on the disk.
2. Another look at the code for the solution
2.1 Image cache, download operation cache, sandbox cache path
Nsuserdomainmask, YES) Lastobject]
Stringbyappendingpathcomponent:[url Lastpathcomponent]]
2.2 Images before downloading the query cache section:
The uiimageuiimage *image = Self.images[app.icon] of the image URL is taken from the images cache first;
Does not exist: The description picture has not been downloaded successfully, or downloaded successfully but the cache in images
[UIImage imagenamed:@ "placeholder"];//download image [self Download:app.icon indexpath:indexpath]; } }
2.3 Download part of the picture:
/** * Download image * @param imageUrl image URL */-(void) Download: (NSString *) imageUrl Indexpath: (Nsindexpath *)
indexpath{
Remove the download operation for the current picture URL (Operation object) nsblockoperation *operation = Self.operations[imageurl];
if (operation) return;
Create action, download picture __weak typeof (self) appsvc = self; Operation = [Nsblockoperation blockoperationwithblock:^{
Nsurl *url = [Nsurl Urlwithstring:imageurl];
NSData *data = [nsdata datawithcontentsofurl:url];//download UIImage *image = [UIImage imagewithdata:data]; NSData
-UIImage//back to main thread [[Nsoperationqueue Mainqueue] addoperationwithblock:^{
if (image) {
If there is a picture (download complete), store the picture to the picture cache dictionary
Medium Appsvc.images[imageurl] = image;
//1 the picture into a sandbox. First convert the picture to NSData nsdata *data = uiimagepngrepresentation
(image);
2. Regenerate cache path [data writetofile:cachedimagefile (IMAGEURL)
Atomically:yes]; }//Remove the download operation from the dictionary (to ensure that the download fails,
can be re-downloaded) [appsvc.operations Removeobjectforkey:imageurl];
Refresh the current table to reduce system overhead [Appsvc.tableview reloadrowsatindexpaths:@
[Indexpath]
Withrowanimation:uitableviewrowanimationnone]; }]; }];
Add the download operation to the queue [Self.queue addoperation:operation];
Add the current download operation to the download operation cache (in order to resolve the duplicate download) Self.operations[imageurl] = operation;}
3. What are the points that are noteworthy?
It is important to note that the addition and deletion of cached content is still indispensable.
3.1 About picture caching:
Very simple, successful download, get the picture, the image is added to the image cache; Download failed, nothing to do, anyway, no diagram. In this mechanism, there is no deletion of the cache in the case of an image item, because the picture cache will never be repeated to add more than one picture of the case, the cache as long as there is a corresponding diagram, directly taken to use, will not be downloaded again.
3.2 About the sandbox cache:
Similarly, the sandbox cache is also a reason: there is a diagram to convert it to NSData, write to disk, and corresponding to the unique path, no diagram is not written. So even if you want to download the same picture, because the current URL corresponding to the sandbox path already exists file, so directly take it, will not be downloaded.
But!
The download operation cache is different!
3.3 About the download operation cache
We need to delete the current download operation from the download operation cache immediately after the download callback is complete!
Because you want to avoid the download failure after the situation can not be downloaded again!
Why is it?
Note the time to add the download operation to the download operation cache:
It was at the beginning of the download and not the moment the download was successful!
If added to the cache at the start of the download, this cache includes two scenarios: Download success and download failure:
If the future download succeeds, then we will not come to determine whether the current download operation in the download operation cache This step, before this directly can take the diagram to use, download operation is not in the download operation cache is not any effect.
But! If the future download fails, then there is certainly no corresponding image cache and sandbox cache, it will certainly come to determine whether the current download operation in the download operation cache this step. Unfortunately, it is there because it has not been deleted. If there is nothing else to do, letting go, the pictures that have failed to download will never be downloaded again.
Did you forget that piece of code? Look back at the code (see how good I am):
if (operation) return;//turned and walked, relentlessly
Therefore, whether the download succeeds or fails, the current download operation is removed from the download operation queue in the image download callback: To ensure that if the download fails, you can re-open the corresponding download
The operation is downloaded and logically more rigorous.
4. Last Words
The two mechanisms of asynchronous + caching will make a big difference to the new program. This should be the only way to develop advanced apps.
Small size brother told the process is relatively complete, more important is to learn the idea:
Cache Rating: Memory cache, sandbox cache, download operation cache.
And we have to use the dichotomy often, to take our logic into account.
If we do not realize that the time to add the download operation to the download operation cache is to include both the download success and the download failure, we will not take into account the immediate deletion of the download operation from the download operation cache, which can easily cause a bug. So in the future development, both success and failure should be taken into account, that is, if there must be else!
Detailed caching mechanism for iOS multi-image download