您的位置:首页 > 理论基础 > 计算机网络

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息