NSOperation下载图片-02

有沙盒缓存

  1 #import "HMAppViewController.h"
  2 #import "HMApp.h"
  3 
  4 #define HMAppImageFile(url) [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[url lastPathComponent]]
  5 
  6 @interface HMAppViewController ()
  7 /**
  8  *  模型数组
  9  */
 10 @property (nonatomic, strong) NSArray *apps;
 11 
 12 /**
 13  *  存储icon的url的字典
 14  */
 15 @property (nonatomic, strong) NSMutableDictionary *operations;
 16 
 17 /**
 18  *  全局队列
 19  */
 20 @property (nonatomic, strong) NSOperationQueue *queue;
 21 
 22 /**
 23  *  存储app的图标的字典
 24  */
 25 @property (nonatomic, strong) NSMutableDictionary *images;
 26 @end
 27 
 28 @implementation HMAppViewController
 29 
 30 #pragma mark - 懒加载
 31 - (NSArray *)apps
 32 {
 33     if(!_apps)
 34     {
 35         _apps = [HMApp apps];
 36     }
 37     return _apps;
 38 }
 39 
 40 - (NSMutableDictionary *)operations
 41 {
 42     if(!_operations)
 43     {
 44         _operations = [NSMutableDictionary dictionary];
 45     }
 46     return _operations;
 47 }
 48 
 49 - (NSOperationQueue *)queue
 50 {
 51     if(!_queue)
 52     {
 53         _queue = [[NSOperationQueue alloc] init];
 54     }
 55     return _queue;
 56 }
 57 
 58 - (NSMutableDictionary *)images
 59 {
 60     if(!_images)
 61     {
 62         _images = [NSMutableDictionary dictionary];
 63     }
 64     return _images;
 65 }
 66 
 67 - (void)viewDidLoad
 68 {
 69     [super viewDidLoad];
 70     
 71 }
 72 
 73 - (void)didReceiveMemoryWarning
 74 {
 75     [super didReceiveMemoryWarning];
 76     
 77     // 移除所有的下载操作
 78     [self.queue cancelAllOperations];
 79     [self.operations removeAllObjects];
 80     
 81     // 移除所有的图片缓存
 82     [self.images removeAllObjects];
 83 }
 84 
 85 // 默认是一组
 86 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 87 {
 88     return 1;
 89 }
 90 
 91 // 每一section有多少行
 92 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 93 {
 94     return self.apps.count;
 95 }
 96 
 97 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 98 {
 99     static NSString *ID = @"app";
100     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
101     if(!cell)
102     {
103         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
104     }
105     HMApp *app = self.apps[indexPath.row];
106     cell.textLabel.text = app.name;
107     cell.detailTextLabel.text = app.download;
108     
109     // 先从images缓存中取出图片url对应的UIImage
110     // 取出url对应的图片
111     UIImage *storageImage = self.images[app.icon];
112     
113     if(storageImage) // 说明图片已下载成功过(成功缓存)在内存中
114     {
115         cell.imageView.image = storageImage;
116     }
117     else
118     {
119         // 获取caches的路径,拼接文件路径
120 //        NSString *file = HMAppImageFile(app.icon);
121         
122         // 先从沙盒中取出图片
123         NSData *data = [NSData dataWithContentsOfFile:HMAppImageFile(app.icon)];
124         
125         if(data)
126         {   // 如果沙盒中有值
127             cell.imageView.image = [UIImage imageWithData:data];
128         }
129         else
130         {   // 如果沙盒中没有值
131             // 要么显示已下载好的图片,要么显示占位图片,防止cell的循环利用时显示其它的图片
132             // 占位图,确保image有尺寸,更新时可以显示最新的图片
133             cell.imageView.image = [UIImage imageNamed:@"placeholder"];
134             
135             [self download:app.icon indexPath:indexPath];
136         }
137     }
138     
139     return cell;
140     
141     // 怎么保证一图片(url)不被重复下载
142     // 用字典解决,key-》url,value-》image
143 }
144 
145 /**
146  *  下载图片和刷新UI
147  */
148 - (void)download:(NSString *)imageUrl indexPath:(NSIndexPath *)indexPath
149 {
150     NSBlockOperation *operation = self.operations[imageUrl];
151 //    NSInvocationOperation
152     
153     if(operation) return;
154     
155     // 解决循环强引用
156     __weak typeof(self) appVc = self;
157     
158     operation = [NSBlockOperation blockOperationWithBlock:^{
159 //        [NSThread sleepForTimeInterval:2];
160         
161         // 创建操作,下载app图标,下载图片是耗时的操作
162         NSURL *url = [NSURL URLWithString:imageUrl];
163         NSData *data = [NSData dataWithContentsOfURL:url]; // 下载图片
164         UIImage *image = [UIImage imageWithData:data];     // data->image
165         
166         // 回到主线程刷新UI
167         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
168             // 设置cell图片(在子线程中的cell有可能给循环利用了,这里设置数据不合理)
169             //                    cell.imageView.image = image;
170             
171             // 字典不能存放nil(空)的
172             if(image)
173             {
174                 appVc.images[imageUrl] = image;
175                 
176 #warning 将图片存入沙盒中
177                 // UIImage -> NSData -> File(文件)
178                 NSData *data = UIImagePNGRepresentation(image);
179                 
180                 // 获取caches的路径,拼接文件路径
181 //                NSString *file = HMAppImageFile(imageUrl);
182                 
183                 [data writeToFile:HMAppImageFile(imageUrl) atomically:YES];
184             }
185             
186             
187             // 从字典中移除下载操作
188             [appVc.operations removeObjectForKey:imageUrl];
189             
190             // 刷新表格(刷新cell所在的行)
191             // 这里会调用(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
192             [appVc.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
193         }];
194     }];
195     
196     // 添加操作到队列中
197     [self.queue addOperation:operation];
198     
199     // 添加到字典中(这句代码为了解决重复下载)
200     self.operations[imageUrl] = operation;
201 }
202 
203 // 用户开始拖拽表格时调用
204 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
205 {
206     // 暂停下载
207     [self.queue setSuspended:YES];
208 }
209 
210 // 用户停止拖拽表格时调用
211 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
212 {
213     // 恢复下载
214     [self.queue setSuspended:NO];
215 }
原文地址:https://www.cnblogs.com/fkunlam/p/4344567.html