解决方案:使用SDWebImage:https://github.com/rs/SDWebImage
我有一个UITableView,在滚动时变得非常迟钝。我发现当我正在使用的图像重新出现在屏幕上时会出现延迟。
我正在使用自定义UITableViewCell。这也是它落后的原因吗?
我的自定义UITableViewCell:
我的代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];
tableViewCellActiviteiten *cell = (tableViewCellActiviteiten *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"tableViewCellActiviteiten" owner:self options:nil];
cell = (tableViewCellActiviteiten *)[nib objectAtIndex:0];
}
cell.thetitle.text = [self.alletitels objectAtIndex:indexPath.row];
cell.thesubtitle.text = [self.allesubtitels objectAtIndex:indexPath.row];
NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];
NSURL * imageURL = [NSURL URLWithString:imagePath];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
cell.image.image = image;
return cell;
}
数组的内容:
self.alletitels
包含一个字符串:“活动标题”
self.allesubtitels
包含一个字符串:“Activity Subtitle”
self.alleimages
包含一个网址:“http://m2.myhappygames.com//files/pics/0/Paranormal_Shark_Activity_3.jpg”
有人可以告知可能导致延迟滚动的原因吗?
答案 0 :(得分:9)
问题在于,每次调用tableView: cellForRowAtIndexPath:
方法时,您的代码都会生成图像。每次单元格出现在屏幕上时都会调用此方法,因此如果您滚动得非常快,此方法将开始同步分配大量图像,这将减慢滚动速度。
作为一种快速解决方案,请在View Controller中实施NSCache并将图像存储在其中。
UIImage *image = [_imageCache objectForKey:@indexPath.row];
if (image == nil) {
NSString * imagePath = [self.alleimages objectAtIndex:indexPath.row];
NSURL * imageURL = [NSURL URLWithString:imagePath];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
[_imageCache setObject:image forKey:@indexPath.row];
}
cell.image.image = image;
_imageCahce是您可以实现的视图控制器的实例变量。
希望这有帮助,欢呼!
答案 1 :(得分:6)
这两行:
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
是什么会大大降低您的桌面效果。
每次刷新该单元格时,您都在同步获取和加载图像数据。
以某种方式缓存(或保存在本地)要显示的图像会更聪明。如果它们没有保存在本地或缓存中,那么只需要获取这些图像(并在“cellForRowAtIndexPath:
”方法之外进行异步处理。)
答案 2 :(得分:4)
在创建单元格时,您正在进行同步网络调用以下载图像。这些调用会阻塞主线程,直到下载单元格为止。延迟时间将根据网络质量而有所不同。
解决方法是使用称为“延迟加载”的技术。在该技术中,图像加载将在单独的线程上进行,从而解除对主线程的阻塞。下载图像,然后将其应用于正确的容器UIImageView
。这是Apple sample code,用于在表格视图中延迟加载图像。
您也可以使用SDWebImage。这也将为您进行图像缓存。
#import <SDWebImage/UIImageView+WebCache.h>
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
return cell;
}
希望有所帮助!
答案 3 :(得分:3)
除了缓存之外,您还可以考虑使用Grand central dispatch在后台加载图像。加载单元格后,放入UIActivityIndicator,然后用单独的线程中的图像替换它。
// get a data provider referencing the relevant file
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(filename);
// use the data provider to get a CGImage; release the data provider
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO,
kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
// make a bitmap context of a suitable size to draw to, forcing decode
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
unsigned char *imageBuffer = (unsigned char *)malloc(width*height*4);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext =
CGBitmapContextCreate(imageBuffer, width, height, 8, width*4, colourSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
CGColorSpaceRelease(colourSpace);
// draw the image to the context, release it
CGContextDrawImage(imageContext, CGRectMake(0, 0, width, height), image);
CGImageRelease(image);
// now get an image ref from the context
CGImageRef outputImage = CGBitmapContextCreateImage(imageContext);
// post that off to the main thread, where you might do something like
// [UIImage imageWithCGImage:outputImage]
[self performSelectorOnMainThread:@selector(haveThisImage:)
withObject:[NSValue valueWithPointer:outputImage] waitUntilDone:YES];
// clean up
CGImageRelease(outputImage);
CGContextRelease(imageContext);
free(imageBuffer);
您还可以使用UIImage + ImmediateLoad.m 它立即解码图像。除了UIImage -initWithContentsOfFile:, - imageWithCGImage:和CG *在iOS4之后是线程安全的。
答案 4 :(得分:2)
您正在尝试在滚动的同一UI线程上加载图像。您应该将它们加载到后台缓存中,然后在准备好显示时从缓存中获取。
答案 5 :(得分:2)
我有一个类似的问题,我用Profiler检查过,所以这里有几个问题:
1)您使用的Reuseable Indentifier错误,您应该始终使用相同的标识符。
而不是:
NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d",indexPath.row,indexPath.section];
使用它:
NSString *CellIdentifier = @"MyIdentifier";
了解更多内容:how to use UItableViewCell reuseIdentifier
2)loadNibNamed方法非常慢(加上你每次为每个单元加载它),你应该摆脱nib,并通过覆盖UITableViewCell的这个方法来放置代码中的UI元素
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;
3)使用Instruments
答案 6 :(得分:2)
您正在为每个图像进行同步网络呼叫这就是您在应用中遇到延迟的问题。试试AsyncImageView 它将从Web异步下载您的图像。并且您将能够从您的应用程序中删除延迟。 : - )