IOS "multithreading-Download data display case (level two cache)/analog sdwebimage Internal implementation"

Source: Internet
Author: User

#import "ViewController.h" #import "WZYApp.h" @interface Viewcontroller ()//Data Model array @property (nonatomic, Strong) Nsarray *apps;//Save the Dictionary @property (nonatomic, strong) nsmutabledictionary *operations;//memory Cache @property (Nonatomic, Strong) Nsmutabledictionary *images;//Operation Queue (prevents duplicate creation) @property (nonatomic, strong) Nsoperationqueue *queue; @end @implementation viewcontroller//Storage Operation-(Nsmutabledictionary *) operations{if (_operations = = nil) {_operations = [nsmutabledicti    Onary dictionary]; } return _operations;}    -(Nsoperationqueue *) queue{if (_queue ==nil) {_queue = [[Nsoperationqueue alloc]init]; } return _queue;}    -(Nsmutabledictionary *) images{if (_images = = nil) {_images = [nsmutabledictionary dictionary]; } return _images;} -(Nsarray *) apps{if (_apps = = nil) {//load plist file Nsarray *array = [Nsarray arraywithcontentsoff                Ile:[[nsbundle Mainbundle] pathforresource:@ "Apps.plist" Oftype:nil]]; Dictionary Arrays--moduloType array Nsmutablearray *arraym = [Nsmutablearray array];        For (nsdictionary *dict in array) {[Arraym Addobject:[wzyapp appwithdict:dict]];    } _apps = Arraym; } return _apps;} -(Nsinteger) Numberofsectionsintableview: (UITableView *) tableview{return 1;} -(Nsinteger) TableView: (UITableView *) TableView numberofrowsinsection: (nsinteger) section{return self.apps.count;} -(UITableViewCell *) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) indexpath{NSLog (@ "---%        @ ", [Nssearchpathfordirectoriesindomains (Nscachesdirectory, Nsuserdomainmask, YES) lastobject]);        01 Create cell static NSString *id = @ "App";        UITableViewCell *cell = [TableView dequeuereusablecellwithidentifier:id];    02 Set the data of the cell//2.1 get the data corresponding to the row cell wzyapp *appm = Self.apps[indexpath.row];    2.2 Set Title Cell.textLabel.text = Appm.name;    2.3 Set sub-title Cell.detailTextLabel.text = Appm.download; 2.4 Setting Pictures//Memory slowSave (refer to a dictionary attribute) thought/* 001 When the picture is downloaded, you need to save the picture to the memory cache 002 When you need to display the picture, first check the local cache when the image has been downloaded 003 If the cache has the picture, set the 004 directly The cache does not change the picture, you need to download the picture * *//disk cache (under the sandbox caches) ideas/* 001 When the picture is downloaded, save to the memory cache, you need to keep a copy to the disk cache 002 when the picture needs to be displayed First, check the memory cache, if there is data in the memory cache, then directly set 003 If there is no data in the memory cache, then check the disk cache 004 If there is data, then directly set it can be | Save a copy into the memory cache 005 If there is no data, then download the data at this time *///Improve the cache structure (memory cache---> Level two cache structure [memory Cache-Sandbox cache]) UIImage *image = [self.images o    BjectForKey:appM.icon];        If there is data in the if (image) {//memory cache, the data is set directly cell.imageView.image = Image;    NSLog (@ "%ZD line cell corresponding image already exists, directly use memory cache", Indexpath.row); } else {///memory cache does not have data//Get disk cache path (three steps) nsstring *caches = [Nssearchpathfordirectoriesindomains (nscachesdirect        Ory, Nsuserdomainmask, YES) lastobject]; NSString *filename = [Appm.icon lastpathcomponent]; Get the last node in the URL (get the full file name from the path with the suffix) nsstring *fullpath = [caches stringbyappendingpathcomponent:filename];    Stitching the Sandbox cache path (stitching the above two strings)//check the disk cache    NSData *data = [NSData datawithcontentsoffile:fullpath];//data = nil; if (data) {///disk cache is available (simulates two reboots, the memory cache is emptied, but the disk cache is still in place, so the data is presented before saving a copy of the data into the memory cache)//display picture UIImage *image =            [UIImage Imagewithdata:data];                        Cell.imageView.image = image;                          Save a copy into the memory cache [Self.images setobject:image ForKey:appM.icon];        NSLog (@ "%zd row cell corresponds to a picture using disk cache", indexpath.row); } else {//disk cache has no data (simulates the first entry to the program, both the memory cache and the disk cache are empty.) First download the data, then display the data, then save a copy of the data to the memory cache, and then save a copy of the data to the disk cache)//solve the data confusion problem (cell and its internal data will be reused due to cell reuse)//Solution 001 CEL L.imageview.image = nil; (but this is not good, if the speed is very card, users will think no picture exists//solution 002 Set placeholder picture, such as line code cell.imageView.image = [UI            Image imagenamed:@ "snip20160712_43"]; Solve the picture repeat download problem (because the user may drag and drop the interface, when the cell repeatedly appears in the field of view and the network speed is slow, the first time the cell enters the time has been created the operation to download the picture, but when the cell again into the field of view and the first download has not been completed, Then it will be repeated two times to download. )//Solution: First check whether the download of the picture already exists//if there is a waiting line (intercept two downloads)//if not presentEncapsulation operation and added to the queue (for first download) nsblockoperation *download = [Self.operations ObjectForKey:appM.icon]; if (download = = nil) {//If the operation does not exist//encapsulation operation nsblockoperation *download = [Nsblockoperation bloc                                        koperationwithblock:^{Nsurl *url = [Nsurl URLWithString:appM.icon];                    for (Nsinteger i = 0; i<1000000000; i++) {//simulate downloading the picture takes a long time | Bad network situation }//download operation NSData *data = [NSData Datawithcont                    Entsofurl:url];                                        UIImage *image = [UIImage imagewithdata:data]; if (image = = nil) {//Resolves a memory cache error when image is empty (if the data has been modified, the URL is modified, the URL is still there but the picture is not, and if you do then save the image to the memory cache (that is, the word In the code), it will be an error. Because nil cannot be stored in the dictionary.                                         )//Solution://To add a decision if statement, if the data does not exist, do not assign value, directly return       Troubleshoot network card download failure scenario download problem//Solution://Remove the operation from the cache (if the network is interrupted during the download, causing the download to fail, The download operation has been created, but the downloading task has not been completed. At this point two times the network, the download operation again, will not continue to download. Why is it? Because the picture is prevented from being downloaded repeatedly, the operation is not created again after it has been created. In this case, the operation must be emptied in the if of the decision Image==nil. That is, if the image is not set successfully, then the download operation is emptied, and the download is added again the next time it is downloaded.                        ) [Self.operations RemoveObjectForKey:appM.icon];                    return;                     }//Save the picture in the memory cache [Self.images setobject:image ForKey:appM.icon];                                        NSLog (@ "Download%zd line cell corresponding picture", Indexpath.row);                                        Save a copy to the disk cache [data Writetofile:fullpath atomically:yes]; [[Nsoperationqueue Mainqueue] addoperationwithblock:^{//Resolve picture does not display the problem (dragging TableView is not displayed.) Why is it? Because it is executed asynchronously, the cell is returned without waiting for the cell.imageView.image setting to succeed.                )//Solution://Manually refresh the current row of the cell so that the data is displayed without dragging.        [TableView Reloaddata]; Refreshes the entire tableView, consumes memory resources, does not recommend [TableView Reloadrowsatindexpaths:@[indexpath] Withrowanimation:uitablevie Wrowanimationfade];                Refresh current Line}];                                }];                                Cache the operation (use a dictionary to receive the save Operation object, avoid repeatedly creating consumption memory) [Self.operations setobject:download ForKey:appM.icon];                Add an action to the queue (the contents of the action)//Save the download to a child thread to execute, to resolve the UI lag problem.            [Self.queue Addoperation:download];            } else {//If the action does not exist//wait for NSLog (@ "%ZD line corresponding picture is already downloading, please wait ....", Indexpath.row); }}}//03 returns cell return cell;}

We do not need to write the above operation, because it is very cumbersome, and the situation is limited to consider. We can use the third-party framework Sdwebimage to help us achieve the download image level two cache operation. The framework also handles a lot of bugs that we don't think about at the moment. It saves a lot of tedious work. The above set Cell.imageView.image operation total of more than 100 lines, we can use the following line of code to fix:

[Cell.imageview sd_setimagewithurl:[nsurl URLWithString:appM.icon] placeholderimage:[uiimage imagenamed:@ " Snip20160712_43 "];

Note One thing:

Directly with the sdwebimage to set the image, if it is set on the tableview above, then because the size of the ImageView is not set up in advance to create some problems, so we need to set the size of the Cell.imageview in advance. Then you need to customize the cell. (Sdwebimage This framework is a service in many places, not just tableview one, so the bug will appear, and the author also proposed a solution)


IOS "multithreading-Download data display case (level two cache)/analog sdwebimage Internal implementation"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.