iOS UITableViewCell 多线程 网络+沙盒的图片加载以及第三方框架SDWebImage方式加载
2015-09-17 21:17
881 查看
1.多线程网络沙盒 方式加载UITableViewCell中的图片
1.首先,在apps.plist存放待加载图片的属性信息,如:2.新建类 App作为数据模型,用来将之前的apps.plist转换成该模型
App.h
#import <Foundation/Foundation.h> @interface App : NSObject /** * 字典里面的key和实体的属性名要一样 */ @property (nonatomic,copy) NSString *name;//图片名 @property (nonatomic,copy) NSString *download;//下载次数 @property (nonatomic,copy) NSString *icon;//图片url +(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.在storyboard中拖入UITableView控件,并设置其代理和数据源代理,导出到ViewController中,在ViewController.h中添加相应的协议
@interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> @end
3.ViewController.h中,导入App.h, 并定义属性,详细如下:
#import "ViewController.h" #import "App.h" @interface ViewController () //存放所有的实体数据 @property (nonatomic,strong) NSMutableArray *apps; //创建下载图片的队列 @property (nonatomic,strong) NSOperationQueue *queue; @property (weak, nonatomic) IBOutlet UITableView *tableView; //定义一个字典,缓存所有下载的图片 key:是图片的下载地址 value:具体图片 @property (nonatomic,strong) NSMutableDictionary *images; //定义一个字典,存放所有正在下载的操作 @property (nonatomic,strong) NSMutableDictionary *downLoadOperation; @end
4.对需要用到的成员懒加载
-(NSMutableDictionary *)downLoadOperation { if(!_downLoadOperation) { _downLoadOperation = [[NSMutableDictionary alloc]init]; } return _downLoadOperation; } //懒加载的方式,当调用对象的get方法就会执行 -(NSMutableDictionary *)images { if(!_images) { _images = [[NSMutableDictionary alloc]init]; } return _images; } -(NSOperationQueue *)queue { if(!_queue) { self.queue = [[NSOperationQueue alloc]init]; } return _queue; } //懒加载的方式,当调用对象的get方法就会执行 -(NSMutableArray *)apps { if(!_apps) { //加载plist文件的数据 _apps = [[NSMutableArray alloc]init]; //找到文件的位置 NSString *fileName = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; //根据文件名称,直接创建字典数据 NSArray *dictArray = [NSArray arrayWithContentsOfFile:fileName]; //把字典数据转换成实体对象 [dictArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSDictionary *dict = (NSDictionary *)obj; App *temp = [App appWithDict:dict]; [_apps addObject:temp]; }]; // //把字典数据转换成实体对象 // for (NSDictionary *dict in dictArray) { // App *temp = [App appWithDict:dict]; // [_apps addObject:temp]; // } } return _apps; }
5.设置UITableView代理方法:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.apps count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: 4000 (NSIndexPath *)indexPath { // 0.用static修饰的局部变量,只会初始化一次 static NSString *ID = @"app"; // 1.拿到一个标识先去缓存池中查找对应的Cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; // 2.如果缓存池中没有,才需要传入一个标识创建新的Cell if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } App *tmp = self.apps[indexPath.row]; cell.textLabel.text = tmp.name; cell.detailTextLabel.text = tmp.download; //从字典缓存中获取已经下载的图片 UIImage *realImage = self.images[tmp.icon]; if(realImage) { cell.imageView.image = realImage; }else { //开始给图片设置占位图片 cell.imageView.image = [UIImage imageNamed:@"placeholder"]; //先从沙盒加载数据 //把图片保存到沙盒中 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] ; NSLog(@"%@",path); //获取文件名 NSString *picName = [tmp.icon lastPathComponent]; //文件在沙盒中的位置 NSString *filePath = [path stringByAppendingPathComponent:picName]; NSData *datas = [NSData dataWithContentsOfFile:filePath]; if(datas) { //如果沙盒里面有数据,加载沙盒数据到表格,同时更新图片集合的字典 UIImage *currImage = [UIImage imageWithData:datas]; cell.imageView.image = currImage; self.images[tmp.icon] = currImage; }else{ //下载,另写一个方法用来调用 [self downLoad:tmp.icon indexPath:indexPath]; } } return cell; } -(void)downLoad:(NSString *)icon indexPath:(NSIndexPath *)path { //判断是否重复下载 NSBlockOperation *operation = self.downLoadOperation[icon]; if (operation) { //如果operation操作已经存在 return; } //开启线程下载图片 __block UIImage *tmpImage = nil; operation = [NSBlockOperation blockOperationWithBlock:^{ @try { //下载图片 NSURL *url1 = [NSURL URLWithString:icon]; NSData *data1 = [NSData dataWithContentsOfURL:url1]; tmpImage = [UIImage imageWithData:data1]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ if (tmpImage) { //刷新表格 //往字典里面存放值 self.images[icon] = tmpImage; //刷新表格 [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationLeft]; //把图片保存到沙盒中 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] ; NSLog(@"%@",path); //获取文件名 NSString *picName = [icon lastPathComponent]; //文件在沙盒中的位置 NSString *filePath = [path stringByAppendingPathComponent:picName]; [data1 writeToFile:filePath atomically:YES]; } }]; } @catch (NSException *exception) { //往字典里面存放值 [self.images removeObjectForKey:icon]; } @finally { //下载完成,移除当前正在下载图片的操作 [self.downLoadOperation removeObjectForKey:icon]; } }]; [self.queue addOperation:operation]; //将当前正在下载的操作添加到字典 self.downLoadOperation[icon]=operation; }
2.使用第三方框架SDWebImage实现上述功能
1.对之前的工程稍作修改即可:github上搜索并下载SDWebImage,导入到Xcode中,然后在ViewController中导入其中的UIImageView+WebCache.h:2.只需保留ViewController中icon数组属性
//存放所有的实体数据 @property (nonatomic,strong) NSMutableArray *apps;
并对其懒加载
//懒加载的方式,当调用对象的get方法就会执行 -(NSMutableArray *)apps { if(!_apps) { //加载plist文件的数据 _apps = [[NSMutableArray alloc]init]; //找到文件的位置 NSString *fileName = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"]; //根据文件名称,直接创建字典数据 NSArray *dictArray = [NSArray arrayWithContentsOfFile:fileName]; //把字典数据转换成实体对象 [dictArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSDictionary *dict = (NSDictionary *)obj; App *temp = [App appWithDict:dict]; [_apps addObject:temp]; }]; } return _apps; }
3.设置表格数据源的时候,只要把设置cell的imageView的image的代码替换成框架里提供的方法即可:
UIImage *placeImage = [UIImage imageNamed:@"placeholder"]; NSURL *url = [[NSURL alloc]initWithString:tmp.icon]; [cell.imageView sd_setImageWithURL:url placeholderImage:placeImage];
详细如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 0.用static修饰的局部变量,只会初始化一次< # # > static NSString *ID = @"app"; // 1.拿到一个标识先去缓存池中查找对应的Cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; // 2.如果缓存池中没有,才需要传入一个标识创建新的Cell if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; } App *tmp = self.apps[indexPath.row]; cell.textLabel.text = tmp.name; cell.detailTextLabel.text = tmp.download; UIImage *placeImage = [UIImage imageNamed:@"placeholder"]; NSURL *url = [[NSURL alloc]initWithString:tmp.icon]; [cell.imageView sd_setImageWithURL:url placeholderImage:placeImage]; //也有功能较为全面的方法 // [cell.imageView sd_setImageWithURL:url // placeholderImage:placeImage // options:SDWebImageRetryFailed // progress:^(NSInteger receivedSize, NSInteger expectedSize) { // NSLog(@"下载进度--%f",(double)receivedSize/expectedSize); // } // completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { // NSLog(@"图片下载完成!"); // }]; return cell; }
相关文章推荐
- Python3写爬虫(四)多线程实现数据爬取
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- C#实现多线程的同步方法实例分析
- 浅谈chuck-lua中的多线程
- C#简单多线程同步和优先权用法实例
- C#多线程学习之(四)使用线程池进行多线程的自动管理
- C#多线程编程中的锁系统(三)
- C#多线程学习之(六)互斥对象用法实例
- 基于一个应用程序多线程误用的分析详解
- C#多线程学习之(三)生产者和消费者用法分析
- C#多线程学习之(一)多线程的相关概念分析
- C#多线程之Thread中Thread.IsAlive属性用法分析
- C#控制台下测试多线程的方法
- Ruby 多线程的潜力和弱点分析