// // ViewController.m // 06-表格图片下载 // // Created by jerry on 15/9/7. // Copyright (c) 2015年 jerry. All rights reserved. // /** * 代码重构 * * 目的:1.如果代码太长,如果有一部分专门解决某一个问题,就单拿出来 * 写的时候,如果思路清晰,能够一次性写完,但是也要注意重构 * 时间长了,不好阅读 * 重构代码,便于维护 * * 重构的方法: * 如果有一部分代码专门解决某一个问题 ,就单拿出来 * 1.新建一个方法-->单一功能拿出来 * 2.参数-->需要传参数 * 3.在原来的代码地方调用,抽取的方法。 * 4.注意测试。 * 5.注意if嵌套,在实际开发中,非常忌讳很深的嵌套,能优化的话最好优化, */ #import "ViewController.h" #import "ZPApp.h" @interface ViewController () // PLIST 文件数据容器 @property(nonatomic,copy)NSArray *appList; // 全局队列 @property(nonatomic,strong)NSOperationQueue *opQueue; // 缓冲池 所有下载操作的缓冲池 @property(nonatomic,strong)NSMutableDictionary *operationCache; // 所有图片的缓存 @property(nonatomic,strong)NSMutableDictionary *imageCache; @end @implementation ViewController -(NSMutableDictionary *)imageCache { if (_imageCache == nil) { _imageCache = [NSMutableDictionary dictionary]; } return _imageCache; } -(NSMutableDictionary *)operationCache { if (_operationCache == nil) { _operationCache = [NSMutableDictionary dictionary]; } return _operationCache; } -(NSOperationQueue *)opQueue { if (_opQueue == nil) { _opQueue = [[NSOperationQueue alloc]init]; } return _opQueue; } -(NSArray *)appList { if (_appList == nil) { //获取文件路径 NSString *str = [[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil]; NSArray *fileArray = [NSArray arrayWithContentsOfFile:str]; NSMutableArray *muArray = [NSMutableArray array]; for ( NSDictionary *dict in fileArray) { ZPApp *app = [ZPApp appWithDict:dict]; [muArray addObject:app]; } _appList = muArray; } return _appList; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.appList.count; } /** * CELL里面的imageview属于懒加载 * 问题1:如果网络比较慢,会比较卡 * 解决办法:用异步下载 * * 问题2:imageview没有frame * 解决办法:使用一个占位图,异步下载完成以后,不显示。(如果占位图比较大,自定义cell) * * 问题3:如果图片下载速度不一致,同时用户浏览快速滚动的时候,会因为cell的重用导致图片混乱。 * 解决办法:MVC使用模型保持下载图像。再次刷新表格 * * 问题4:在用户快速滚动的时候会重复添加下载操作到队列里。 * 解决办法:建立一个下载操作的缓冲池,首先检查缓冲池里是否有当前这个下载操作,有的话就不用创建,没有的时候在下载。保证一个图片只对应一个下载操作。 * * 问题5:将图像保存到模型里有缺点: * 优点:不用重复下载,利用mvc刷新表格,不会造成数据混乱。加载速度比较快 * 缺点:内存消耗比较大,因为所有下载好的图像都会记录在模型里。如果数据比较多(20000),就会造成很大的内存警告 * * 问题6:图像跟模型耦合性太强,导致清理内存非常困难 * 解决办法:模型根图像分开,在控制器里边做缓存。 * * 问题7:下载操作缓冲池,会越来越大,想办法清理 * 解决办法: */ -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 创建cell的标识 static NSString *ID = @"AppCell"; // 查找缓存池中有没有标识为ID的cell 如果有直接拿来用 如果没有创建一个 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID]; } // 给cell 设置数据 ZPApp *app = self.appList[indexPath.row]; cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; // 判断模型里边是否有图像 if ([self.imageCache objectForKey:app.icon]) { // --如果模型里面有图像,直接给cell的imageview赋值。 NSLog(@"none"); // cell.imageView.image = app.image; cell.imageView.image = self.imageCache[app.icon]; }else{ // 下载图片 // [NSThread sleepForTimeInterval:0.5]; // NSLog(@"正在下载....."); // 现实占位图 cell.imageView.image = [UIImage imageNamed:@"user_default"]; #warning 从这里开始剪的代码 // 下载图片 [self downloadImage:indexPath]; } // 异步执行下载,不需要等待,会直接执行return cell 也就是先初始化一个没有图片的cell 在表格上现实,后来把图片下载完成以后,给cell的imageview属性重新赋值。 return cell; } /** * 下载图片 * * @param indexPath <#indexPath description#> */ - (void)downloadImage:(NSIndexPath *)indexPath { ZPApp *app = self.appList[indexPath.row]; // 如果下载缓冲池里面有当前图片的下载操作,就不用创建下载操作,没有的话才需要 创建下载操作 #warning 缓冲池中的字典创建 key:是图片的url地址,因为这个地址是唯一的,而且是明确的。value:下载操作 if (self.operationCache[app.icon]) { NSLog(@"已加入缓冲池,正在玩命下载中。。。"); return; } // 缓冲池没有下载操作。 // 异步下载图片 NSBlockOperation *downloadOp = [NSBlockOperation blockOperationWithBlock:^{ // 1.下载图片(二进制) NSURL *url = [NSURL URLWithString:app.icon]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *img = [UIImage imageWithData:data]; // app.image = img; // 把下载好的图片保存到模型。 // 字典的赋值不能为nil, // 将下载好的数据保存到集合里 if (img) { [self.imageCache setObject:img forKey:app.icon]; } // 将操作从操作缓冲池删除 [self.operationCache removeObjectForKey:app.icon]; // 更新ui [[NSOperationQueue mainQueue]addOperationWithBlock:^{ // cell.imageView.image = app.image; // 刷新当前行 reload会重新调用cell的初始化方法。重新判断模型里面是否有图像,有的话直接显示 [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; }]; }]; [self.opQueue addOperation:downloadOp]; // 将当前图片的下载操作,存放到缓冲池中。 [self.operationCache setObject:downloadOp forKey:app.icon]; } /** * 真正开发中一定要注意这个方法 */ -(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; //当给了内存警告之后,一定要在这里做些内存清理的操作,如果不处理程序直接会被系统强制退出。 // 清理图片内存 [self.imageCache removeAllObjects]; // 清理操作缓冲 [self.operationCache removeAllObjects]; // 取消下载队列里的人物 [self.opQueue cancelAllOperations]; } @end
model .h
// // ZPApp.h // 06-表格图片下载 // // Created by jerry on 15/9/7. // Copyright (c) 2015年 jerry. All rights reserved. // // xcode 6 pch #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface ZPApp : NSObject @property(nonatomic,copy)NSString *name; @property(nonatomic,copy)NSString *icon; @property(nonatomic,copy)NSString *download; //@property(nonatomic,strong) UIImage *image; +(instancetype)appWithDict:(NSDictionary *)dict; @end
.m
// // ZPApp.m // 06-表格图片下载 // // Created by jerry on 15/9/7. // Copyright (c) 2015年 jerry. All rights reserved. // #import "ZPApp.h" @implementation ZPApp +(instancetype)appWithDict:(NSDictionary *)dict { ZPApp *app = [[self alloc]init]; [app setValuesForKeysWithDictionary:dict]; return app; } @end
plist文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>name</key> <string>植物大战僵尸</string> <key>icon</key> <string>http://p16.qhimg.com/dr/48_48_/t0125e8d438ae9d2fbb.png</string> <key>download</key> <string>10311万</string> </dict> <dict> <key>name</key> <string>捕鱼达人2</string> <key>icon</key> <string>http://p19.qhimg.com/dr/48_48_/t0101e2931181bb540d.png</string> <key>download</key> <string>9982万</string> </dict> <dict> <key>name</key> <string>保卫萝卜</string> <key>icon</key> <string>http://p17.qhimg.com/dr/48_48_/t012d281e8ec8e27c06.png</string> <key>download</key> <string>8582万</string> </dict> <dict> <key>name</key> <string>找你妹</string> <key>icon</key> <string>http://p18.qhimg.com/dr/48_48_/t0184f949337481f071.png</string> <key>download</key> <string>5910万</string> </dict> <dict> <key>name</key> <string>水果忍者</string> <key>icon</key> <string>http://p17.qhimg.com/dr/48_48_/t015f10076f95e27e74.png</string> <key>download</key> <string>5082万</string> </dict> <dict> <key>name</key> <string>鳄鱼小顽皮</string> <key>icon</key> <string>http://p16.qhimg.com/dr/48_48_/t01885f5596e1d30172.png</string> <key>download</key> <string>3918万</string> </dict> <dict> <key>name</key> <string>神偷奶爸</string> <key>icon</key> <string>http://p19.qhimg.com/dr/48_48_/t0164ad383c622aabef.png</string> <key>download</key> <string>3681万</string> </dict> <dict> <key>name</key> <string>时空猎人</string> <key>icon</key> <string>http://p17.qhimg.com/dr/48_48_/t017bc3cfcf3981b197.png</string> <key>download</key> <string>3645万</string> </dict> <dict> <key>name</key> <string>愤怒的小鸟</string> <key>icon</key> <string>http://p18.qhimg.com/dr/48_48_/t012fea7312194537c2.png</string> <key>download</key> <string>3552万</string> </dict> <dict> <key>name</key> <string>滑雪大冒险</string> <key>icon</key> <string>http://p18.qhimg.com/dr/48_48_/t01e61cbba53fb9eb82.png</string> <key>download</key> <string>3487万</string> </dict> <dict> <key>name</key> <string>爸爸去哪儿</string> <key>icon</key> <string>http://p18.qhimg.com/dr/48_48_/t0108c33d3321352682.png</string> <key>download</key> <string>3117万</string> </dict> <dict> <key>name</key> <string>我叫MT </string> <key>icon</key> <string>http://p17.qhimg.com/dr/48_48_/t01077fd80ffb5c8740.png</string> <key>download</key> <string>2386万</string> </dict> <dict> <key>name</key> <string>3D终极狂飙</string> <key>icon</key> <string>http://p17.qhimg.com/dr/48_48_/t01f55acd4a3ed024eb.png</string> <key>download</key> <string>2166万</string> </dict> <dict> <key>name</key> <string>杀手2</string> <key>icon</key> <string>http://p16.qhimg.com/dr/48_48_/t018f89d6e0922f75a1.png</string> <key>download</key> <string>1951万</string> </dict> <dict> <key>name</key> <string>俄罗斯方块</string> <key>icon</key> <string>http://p0.qhimg.com/dr/48_48_/t0183a670f1dbff380f.png</string> <key>download</key> <string>1290万</string> </dict> <dict> <key>name</key> <string>刀塔传奇</string> <key>icon</key> <string>http://p16.qhimg.com/dr/48_48_/t01c3f62a27c3de7af5.png</string> <key>download</key> <string>1249万</string> </dict> </array> </plist>
时间: 2024-10-11 18:44:17