ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
滚动列表cell的图片从服务器上下载显示,利用多线程和缓存技术 高效下载显示图片。 cell下载图片思路: ![](https://box.kancloud.cn/2016-03-07_56dd4010f2ebe.jpg) 1、定义images字典存放下载后的图片(图片下载url作为key,图片作为value)cell图片先去images字典中找,没有就往下(沙盒中查找)。 2、查找沙盒是否存在,若存在就设置cell图片,否则显示占位图片(增强体验感)并开启线程下载图片。 3、定义字典operations存放所有的下载操作(url是key,operation对象是value)。判断下载操作是否存在,若存在 说明下载中,否则创建下载操作。 4、下载完成后,更新主线程:将图片添加存放图片的images字典中,将操作从operations字典中移除(防止operations越来越大,保证下载失败后,能重新下载),将图片保存到沙盒中,并刷新表格。 案例:应用管理界面cell 1、应用模型  App.h ~~~ #import <Foundation/Foundation.h> @interface App : NSObject //应用名称 @property(nonatomic,copy) NSString *name; //下载量 @property(nonatomic,copy) NSString *download; //图标地址 @property(nonatomic,copy) NSString *icon; +(instancetype)appWithDict:(NSDictionary *)dict; @end ~~~ App.m ~~~ #import "App.h" @implementation App +(instancetype)appWithDict:(NSDictionary *)dict{ App *app = [[App alloc]init]; [app setValuesForKeysWithDictionary:dict]; return app; } @end ~~~ 2、定义队列、存放操作字典、存放图片字典、应用app变量 ~~~ //应用app @property(nonatomic,strong) NSMutableArray *apps; //存放所有下载图片的队列 @property(nonatomic,strong) NSOperationQueue *queue; //存放所有的下载操作(url是key,operation对象是value) @property(nonatomic,strong) NSMutableDictionary *operations; //存放所有下载完的图片 @property(nonatomic,strong) NSMutableDictionary *images; #pragma 懒加载 -(NSMutableArray *)apps{ if (_apps==nil) { NSMutableArray *appArr = [NSMutableArray array]; //取出plist文件转换字典 NSString *file = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; NSArray *dictArr = [NSArray arrayWithContentsOfFile:file]; //字典转模型 for (NSDictionary *dict in dictArr) { App *app = [App appWithDict:dict]; [appArr addObject:app]; } _apps = appArr; } return _apps; } -(NSOperationQueue *)queue{ if (!_queue) { self.queue = [[NSOperationQueue alloc]init]; } return _queue; } -(NSMutableDictionary *)operations{ if (!_operations) { self.operations = [[NSMutableDictionary alloc]init]; } return _operations; } -(NSMutableDictionary *)images{ if (_images) { self.images = [[NSMutableDictionary alloc]init]; } return _images; } ~~~ 3、设置cell,线程下载图片 ~~~ #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.apps.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"app"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } //取出模型 App *app = self.apps[indexPath.row]; //设置cell cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; // 先从images缓存中取出图片url对应的UIImage UIImage *image = self.images[app.icon]; if (image) {// 说明图片已经下载成功过(成功缓存) cell.imageView.image = image; }else{// 说明图片并未下载成功过(并未缓存过) // 获得caches的路径, 拼接文件路径 NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:[app.icon lastPathComponent]]; // 先从沙盒中取出图片 NSData *data = [NSData dataWithContentsOfFile:file]; if (data) {// 沙盒中存在这个文件 cell.imageView.image = [UIImage imageWithData:data]; }else{// 沙盒中不存在这个文件 //显示占位图片 cell.imageView.image = [UIImage imageNamed:@"placeholder"]; // 下载图片 [self download:app.icon indexPath:indexPath]; } } return cell; } -(void)download:(NSString *)imageUrl indexPath:(NSIndexPath *)indexPath{ //取出当前图片url对应下的下载操作(operations对象) NSBlockOperation *operation = self.operations[imageUrl]; if (operation) return; __weak typeof(self) appsVC = self; operation = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:imageUrl]; NSData *data = [NSData dataWithContentsOfURL:url];//下载图片 UIImage *image = [UIImage imageWithData:data];//转化为image //回到住线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ if (image) { //存放到字典中 appsVC.images[imageUrl] = image; //图片存到沙盒中解) //UIImage --> NSData --> File(文件) NSData *data = UIImagePNGRepresentation(image); NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:[imageUrl lastPathComponent]]; NSLog(@"%@",file); [data writeToFile:file atomically:YES]; } // 从字典中移除下载操作 (防止operations越来越大,保证下载失败后,能重新下载) [appsVC.operations removeObjectForKey:imageUrl]; // 刷新表格 [appsVC.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; }]; }]; // 添加操作到队列中 [self.queue addOperation:operation]; // 添加到字典中 (这句代码为了解决重复下载) self.operations[imageUrl] = operation; } ~~~ 4、表格拖拽时停止下载,停止拖拽时开始下载 ~~~ /** * 当用户开始拖拽表格时调用 */ -(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{ //暂停下载 [self.queue setSuspended:YES]; } /** * 当用户停止拖拽表格时调用 */ -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ //恢复下载 [self.queue setSuspended:NO]; } ~~~ 5、内存警告,移除所有缓存字典。 ~~~ - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // 移除所有的下载操作缓存 [self.queue cancelAllOperations]; [self.operations removeAllObjects]; // 移除所有的图片缓存 [self.images removeAllObjects]; } ~~~ 效果: ![](https://box.kancloud.cn/2016-03-07_56dd401135f34.jpg)