UITableView 异步下载图片实例
先来看一下 效果图,有图有真相嘛
本文转自 http://www.999dh.net/article/iphone_ios_art/50.html 如转载,请注明!
在上面的地址中,有工程的下载链接,可以自由下载!
UITableView是可以用来显示图片的,如果图片的数量少,或者是已经集成在app里面的话,那这个处理起来很简单。但是如果图片需要从网上download下来,然后再显示的话,那耗时就比较厉害了。由于下载的速度比较慢,所以如果在主线程里面等待图片的下载并且更新的话,那界面体验非常差。
我这个例子是根据网上的一个名字叫WQTableViewController的例子修改的。在WQTableViewController的例子里面,用到了delete,经过我的修改,并没有用到 delegate,我不清楚为什么他们这么喜欢用delegate,因为我不用也可以实现啊,可能是我对delegate的理解还不够深刻。
WQTableViewController的例子有缺陷,那就是如果当前的cell还没有下载好图片,就算下载好之后,也需要滑动了才能显示,不滑动不显示,我把这个也修改了。
我的思路:先下载imagelist文件,里面存放了需要显示的文字,图片的url等信息。
imagelist文件只下载一次,这里不考虑更新的问题,下载后存放在cache里面,下次启动速度快
图片也是下载到cache里面的。我启动了2个主要的线程,第一个是下载全部图片的线程,第二个是下载当前可见cell对于的图片的线程,并且当前可见cell图片下载完一个就更新界面。这样就算不滑动界面也可以直接更新cell。
代码如下:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIScrollViewDelegate,UITableViewDelegate>
{
NSMutableArray *tableDataArray;
}
@property (strong, nonatomic) IBOutlet UITableView *mytable;
@end
/////////////////////////////////////////////////
//
// ViewController.m
// lazyTableUpdate
//
// Created by Rock 13-1-7.
// Copyright (c) 2013年 All rights reserved.
//
#import "ViewController.h"
#import "SBJson.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize mytable;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(@"Home", @"Home");
}
return self;
}
//下载所有的图片
-(void)downLoadAllImage
{
NSInteger index = 0;
for (index = 0; index < [tableDataArray count]; ++ index )
{
NSString *imageStr = [[[[tableDataArray objectAtIndex:index] valueForKey:@"im:image"] objectAtIndex:0] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:index] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imageDataPath])
{
NSURL *imageUrl = [NSURL URLWithString:[imageStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
[imageData writeToFile:imageDataPath atomically:YES];
}
}
}
//下载当前可见cell的image
-(void)downLoadCurrentImage
{
NSLog(@"downLoadCurrentImage");
NSArray *indexPathsForLoad = [mytable indexPathsForVisibleRows];
for (NSIndexPath *item in indexPathsForLoad)
{
NSInteger rowNumberForCell = item.row;
NSString *imageStr = [[[[tableDataArray objectAtIndex:rowNumberForCell] valueForKey:@"im:image"] objectAtIndex:0] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:rowNumberForCell] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imageDataPath])
{
NSURL *imageUrl = [NSURL URLWithString:[imageStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
[imageData writeToFile:imageDataPath atomically:YES];
[self performSelectorOnMainThread:@selector(refreshUITableView:) withObject:nil waitUntilDone:YES];
}
}
}
//刷新uitableview
-(void)refreshUITableView:(id)data
{
[mytable reloadData];
}
-(void)StartThread
{
[self performSelectorInBackground:@selector(downLoadCurrentImage) withObject:nil];
[self performSelectorInBackground:@selector(downLoadAllImage) withObject:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString * filePath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:@"image_lst.info"]];
//只下载一次
if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSString *jsonStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/limit=75/json"] encoding:NSUTF8StringEncoding error:nil];
NSDictionary *dic = [jsonStr JSONValue];
tableDataArray = [[dic valueForKey:@"feed"] valueForKey:@"entry"];
NSData * data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
[data writeToFile:filePath atomically:YES];
}
else
{
NSLog(@"File Already Exists");
NSString * jsonStr = [[NSString alloc]initWithData:[NSData dataWithContentsOfFile:filePath] encoding:NSUTF8StringEncoding];
NSDictionary *dic = [jsonStr JSONValue];
tableDataArray = [[dic valueForKey:@"feed"] valueForKey:@"entry"];
}
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(StartThread) userInfo:nil repeats:NO];
}
// customize the number of rows in the table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = [tableDataArray count];
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"LazyTableCell";
NSLog(@"cellForRowAtIndexPath");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *item = [tableDataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [[item valueForKey:@"im:name"] valueForKey:@"label"];
cell.detailTextLabel.text = [[item valueForKey:@"summary"] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:indexPath.row] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imageDataPath]];
if (image)
{
cell.imageView.image = image;
}
else
{
cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];//这个图片在工程里面是没有的 如果可以换成那种旋转的等待图片,那效果非常好
}
return cell;
}
//停止滚动之后启动下载当前cell图片的线程
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self performSelectorInBackground:@selector(downLoadCurrentImage) withObject:nil];
}
- (void)viewDidUnload
{
[self setMytable:nil];
mytable = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end
我这个例子是根据网上的一个名字叫WQTableViewController的例子修改的。在WQTableViewController的例子里面,用到了delete,经过我的修改,并没有用到 delegate,我不清楚为什么他们这么喜欢用delegate,因为我不用也可以实现啊,可能是我对delegate的理解还不够深刻。
WQTableViewController的例子有缺陷,那就是如果当前的cell还没有下载好图片,就算下载好之后,也需要滑动了才能显示,不滑动不显示,我把这个也修改了。
我的思路:先下载imagelist文件,里面存放了需要显示的文字,图片的url等信息。
imagelist文件只下载一次,这里不考虑更新的问题,下载后存放在cache里面,下次启动速度快
图片也是下载到cache里面的。我启动了2个主要的线程,第一个是下载全部图片的线程,第二个是下载当前可见cell对于的图片的线程,并且当前可见cell图片下载完一个就更新界面。这样就算不滑动界面也可以直接更新cell。
代码如下:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIScrollViewDelegate,UITableViewDelegate>
{
NSMutableArray *tableDataArray;
}
@property (strong, nonatomic) IBOutlet UITableView *mytable;
@end
/////////////////////////////////////////////////
//
// ViewController.m
// lazyTableUpdate
//
// Created by Rock 13-1-7.
// Copyright (c) 2013年 All rights reserved.
//
#import "ViewController.h"
#import "SBJson.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize mytable;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(@"Home", @"Home");
}
return self;
}
//下载所有的图片
-(void)downLoadAllImage
{
NSInteger index = 0;
for (index = 0; index < [tableDataArray count]; ++ index )
{
NSString *imageStr = [[[[tableDataArray objectAtIndex:index] valueForKey:@"im:image"] objectAtIndex:0] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:index] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imageDataPath])
{
NSURL *imageUrl = [NSURL URLWithString:[imageStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
[imageData writeToFile:imageDataPath atomically:YES];
}
}
}
//下载当前可见cell的image
-(void)downLoadCurrentImage
{
NSLog(@"downLoadCurrentImage");
NSArray *indexPathsForLoad = [mytable indexPathsForVisibleRows];
for (NSIndexPath *item in indexPathsForLoad)
{
NSInteger rowNumberForCell = item.row;
NSString *imageStr = [[[[tableDataArray objectAtIndex:rowNumberForCell] valueForKey:@"im:image"] objectAtIndex:0] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:rowNumberForCell] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
if (![[NSFileManager defaultManager] fileExistsAtPath:imageDataPath])
{
NSURL *imageUrl = [NSURL URLWithString:[imageStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
[imageData writeToFile:imageDataPath atomically:YES];
[self performSelectorOnMainThread:@selector(refreshUITableView:) withObject:nil waitUntilDone:YES];
}
}
}
//刷新uitableview
-(void)refreshUITableView:(id)data
{
[mytable reloadData];
}
-(void)StartThread
{
[self performSelectorInBackground:@selector(downLoadCurrentImage) withObject:nil];
[self performSelectorInBackground:@selector(downLoadAllImage) withObject:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString * filePath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:@"image_lst.info"]];
//只下载一次
if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSString *jsonStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/toppaidapplications/limit=75/json"] encoding:NSUTF8StringEncoding error:nil];
NSDictionary *dic = [jsonStr JSONValue];
tableDataArray = [[dic valueForKey:@"feed"] valueForKey:@"entry"];
NSData * data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
[data writeToFile:filePath atomically:YES];
}
else
{
NSLog(@"File Already Exists");
NSString * jsonStr = [[NSString alloc]initWithData:[NSData dataWithContentsOfFile:filePath] encoding:NSUTF8StringEncoding];
NSDictionary *dic = [jsonStr JSONValue];
tableDataArray = [[dic valueForKey:@"feed"] valueForKey:@"entry"];
}
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(StartThread) userInfo:nil repeats:NO];
}
// customize the number of rows in the table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = [tableDataArray count];
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"LazyTableCell";
NSLog(@"cellForRowAtIndexPath");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSDictionary *item = [tableDataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [[item valueForKey:@"im:name"] valueForKey:@"label"];
cell.detailTextLabel.text = [[item valueForKey:@"summary"] valueForKey:@"label"];
NSString *imageName = [[[[tableDataArray objectAtIndex:indexPath.row] valueForKey:@"im:name"] valueForKey:@"label"] stringByAppendingString:@".temp"];
NSString *imageDataPath = [NSHomeDirectory() stringByAppendingPathComponent:[@"Library/Caches/" stringByAppendingString:imageName]];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imageDataPath]];
if (image)
{
cell.imageView.image = image;
}
else
{
cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];//这个图片在工程里面是没有的 如果可以换成那种旋转的等待图片,那效果非常好
}
return cell;
}
//停止滚动之后启动下载当前cell图片的线程
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self performSelectorInBackground:@selector(downLoadCurrentImage) withObject:nil];
}
- (void)viewDidUnload
{
[self setMytable:nil];
mytable = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
@end