标签:
问题一:如果使用同步下载,那么网速慢的时候会超级卡
问题二:图片没有frame,所以cell初始化的时候,给imageView的frame是0,异步下载完成之后不显示
解决办法:使用占位图(如果占位图比较大,自定义cell可以解决)
cell重用的时候重复多次下载的问题:控制器跳过了模型,直接对view赋值
问题四:在用户快速滚动的时候,会重复添加下载操作到队列
解决办法:建立一个下载操作的缓冲池,首先检查"缓冲池"里是否有当前图片下载操作,如果有,就不在创建了,保证一个图片只对应一个下载操作
将图像保存到模型里优缺点
优点:不用重复下载,利用MVC刷新表格,不会造成数据混乱,加载数据比较快
缺点:内存:所有下载好的图像都会记录在模型里。如果数据比较多(2000个)
造成内存警告
-- *图像跟模型耦合性太强,导致清理内存非常困难
解决办法:模型跟图像分开,在控制器里做缓存
问题6:下载操作缓存池,会越来越大,想办法清理
@interface ViewController () //数据源 @property (nonatomic, strong) NSArray *dataList; //管理全局下载操作队列 @property (nonatomic, strong) NSOperationQueue *opQueue; //所有下载操作的缓冲池 (key:当前图片的url,value下载操作) @property (nonatomic, strong) NSMutableDictionary *operationCache; //所有图片在内存中的缓存 @property (nonatomic, strong) NSCache *imgCache; @end - (NSCache *)imgCache { if (!_imgCache) { _imgCache = [[NSCache alloc] init]; _imgCache.countLimit = 10; } return _imgCache; } - (NSMutableDictionary *)operationCache { if (!_operationCache) { _operationCache = [NSMutableDictionary dictionary]; } return _operationCache; } - (NSOperationQueue *)opQueue { if (_opQueue == nil) { _opQueue = [[NSOperationQueue alloc] init]; } return _opQueue; } - (NSArray *)dataList { if (!_dataList) { NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]]; //字典转模型 NSMutableArray *mulArr = [NSMutableArray array]; for (NSDictionary *dict in array) { [mulArr addObject:[AppModel appWithDict:dict]]; } _dataList = mulArr; } return _dataList; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataList.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID]; } AppModel *app = self.dataList[indexPath.row]; cell.textLabel.text = [app name]; cell.detailTextLabel.text = [app download]; //判断模型里面是否有图像 if ([self.imgCache objectForKey:app.icon]) {//如果模型里面有头像直接赋值 cell.imageView.image = [self.imgCache objectForKey:app.icon]; } else { //显示图片 //如果沙盒里面有图片,直接从沙盒加载 UIImage *image = [UIImage imageWithContentsOfFile:[self cachePathWithUrl:app.icon]]; if (image) { //设置图片缓存到内存,方便下次从内存直接加载 [self.imgCache setObject:image forKey:app.icon]; //显示图片到cell cell.imageView.image = [self.imgCache objectForKey:app.icon]; } else {//沙盒里面没有图片,显示占位图,网上下载 cell.imageView.image = [UIImage imageNamed:@"user_default"]; //下载图片 [self downLoadImg:indexPath]; } } return cell; } - (void)downLoadImg:(NSIndexPath *)indexPath { AppModel *app = self.dataList[indexPath.row]; //如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有才去创建操作 //判断缓冲池中是否存在当前图片的操作 if ([self.operationCache valueForKey:app.icon]) { NSLog(@"正在玩命下载中..."); } else { //没有下载操作 //异步下载图片,直接return cell不需要等待 NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{ //模拟延时 // if (indexPath.row == 6) { // [NSThread sleepForTimeInterval:5]; // } [NSThread sleepForTimeInterval:0.5]; // NSLog(@"正在下载中..."); //下载图片(二进制) NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; UIImage *image = [UIImage imageWithData:data]; //将下载好的数据保存到模型 //字典的赋值不能为nil if (image) { [self.imgCache setObject:image forKey:app.icon]; //将图片写入沙盒 [data writeToFile:[self cachePathWithUrl:app.icon] atomically:YES]; //将操作从操作缓冲池删除 [self.operationCache removeObjectForKey:app.icon]; } //更新UI,应该回到主线程 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ //只设置了image,没有frame,调用layoutSubView()才会给子控件重新布局 //选中某行cell,也会触发layoutSubViews()方法,会给子视图重新布局 // cell.imageView.image = image; //刷新当前行(会重新调用初始化方法,重新判断模型里面是否有图像,有的话直接显示) [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; }]; }]; [self.opQueue addOperation:downloadOp]; NSLog(@"------%li",self.opQueue.operationCount); //将操作添加到缓存池(使用图片的url作为key) [self.operationCache setValue:downloadOp forKey:app.icon]; } } #pragma mark - 在真实开发中,一定要注意这个方法 - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; //需要在这里做一些内存清理工作,如果不处理,会被系统强制杀死(闪退) //清理图片缓存 [self.imgCache removeAllObjects]; //清理操作缓存 [self.operationCache removeAllObjects]; //取消下载队列里面的任务 [self.opQueue cancelAllOperations]; } #pragma mark - 拼接一个文件在沙盒的全路径 - (NSString *)cachePathWithUrl:(NSString *)urlString { //获得缓存的路径 NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; //把路径跟uslString拼接起来 return [cachePath stringByAppendingPathComponent:urlString.lastPathComponent]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"%@",self.operationCache); // for (AppModel *app in self.dataList) { // NSLog(@"==========%@",[self.imgCache valueForKey:app.icon]); // } } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 100; } - (void)dealloc { NSLog(@"dealloc"); }
标签:
原文地址:http://www.cnblogs.com/wuhongxing/p/4993402.html