我有三个不同的细胞。 Cell01,Cell02和Cell03。 Cell01必须只出现一次,位于tableview的顶部,其余的02和03必须插值(02,03,02,03(...))。
问题是滚动TableView时有一些“滞后”。我正在从文档文件夹中加载图像,我也正在调整它以不需要太多处理,但它仍然在缓慢滚动。它正在重复使用单元格(我检查了if(!cell)
)。
这是我的代码:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
if (row == 0) {
Cell01 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:@"Cell01ID"];
if (!cell) {
cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:@"Cell01" owner:self options:nil] objectAtIndex:0];
cell.someLabel.text = @"First";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"mainimage" andSize:CGSizeMake(200, 200)];
}
} else if (row % 2 == 0) {
Cell02 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:@"Cell02ID"];
if (!cell) {
cell = (Cell02 *)[[[NSBundle mainBundle] loadNibNamed:@"Cell02" owner:self options:nil] objectAtIndex:0];
cell.randomLabel.text = @"Second";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"secondimage" andSize:CGSizeMake(200, 200)];
}
} else {
Cell03 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:@"Cell03ID"];
if (!cell) {
cell = (Cell03 *)[[[NSBundle mainBundle] loadNibNamed:@"Cell03" owner:self options:nil] objectAtIndex:0];
cell.anotherLabel.text = @"Third";
cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];
}
}
}
- (UIImage *)imageInDocumentsDirectoryWithName:(NSString *)fileName andSize:(CGSize)size
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:fileName];
UIImage *image = [UIImage imageWithContentsOfFile:path];
image = [image resizedImageToFitInSize:size scaleIfSmaller:YES];
return image;
}
知道如何改进这个tableview(并让它滚动得更快)吗?
答案 0 :(得分:1)
我认为缓慢滚动是由于从文档目录中加载单元格上的图像。从Doc dir获取图像需要一些时间,当你滚动你的表视图时,会创建一个新的单元格并从doc dir加载图像需要一些时间。尝试在单元格上使用延迟加载图像。也可以在不在主线程中的新线程中加载图像..
有一个Apple的示例项目帮助你。 lazy loading table view
我希望这会有所帮助。
答案 1 :(得分:0)
考虑异步加载图像。您可以在可变数组中保留对所有UIImageView
的引用,开始在异步块中加载图像,例如使用GCD,然后在加载时更新图像视图。
这是一个粗略的例子,它看起来如何(假设你有一个ivar NSMutableArray *_imageViews
,用正确的元素大小初始化,并填充nils)。我在这里编写代码,但我希望你能得到这个想法。顺便说一下,你可以通过插入[NSNull null]
来填充nils的可变数组。
我保证如果你正确实现这一点,你会看到滚动速度明显改善:)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
if (row == 0) {
Cell01 *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:@"Cell01ID"];
if (!cell) {
cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:@"Cell01" owner:self options:nil] objectAtIndex:0];
cell.someLabel.text = @"First";
[_imageViews replaceObjectAtIndex:row withObject:cell.someImage];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
UIImage *image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];
// because UI needs to be updated on the main thread,
// dispatch yet another block.
dispatch_async(dispatch_get_main_queue(), ^{
UIIMageView *imageView = [_imageViews objectAtIndex:row];
ImageView.image = image;
});
});
}
// et cetera
}
答案 2 :(得分:0)
我刚刚完成了类似的操作,如果你确保文件目录中的所有图像都已经是正确的大小(200 x 200),那么这将很好地工作,而不必异步加载。
如果您需要更大的图像,则在保存原始文件时生成尺寸正确的缩略图,因为实际需要花费太多处理来调整“真实”图像的大小时间”。
但在这种情况下,您只有三张图片。 如果您只是在调整图像大小并将其重复使用(而不是制作新图像)之后对图像进行缓存,那么它将比此更快。
答案 3 :(得分:0)
您当前的实施存在两个潜在的性能问题。第一种是使用NSBundle
而不是UINib
来加载nib文件。 NSBundle
每次从文件系统重新加载nib文件,而UINib
读取一次nib文件并将其内容缓存在内存中。由于每次都不需要从文件系统重新读取nib,因此使用UINib
实例化对象应该要快几个数量级。
所以不要这样做......
cell = [[[NSBundle mainBundle] loadNibNamed:@"Cell02" owner:self options:nil] objectAtIndex:0];
......这样做:
cell = [UINib loadNibNamed:@"Cell02" owner:self] objectAtIndex:0];
第二个问题是类似的;当前实现每次都从文件系统重新加载相同的图像,而不是将它们缓存在内存中并重用它们。要解决此问题,您可以添加类型为NSArray
或NSDictionary
的实例变量(取决于您希望如何检索图像),然后在加载图像之前进行检查以查看它是否已存在于集合中。如果没有,请在使用之前加载图像并将其存储在集合中。否则,使用缓存的图像而不是再次加载它。
所以不要这样做......
cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];
......做这样的事情:
// Note: Consider defining constants for the keys/filenames.
UIImage *image = [self.cachedImages objectForKey:@"thirdimage"];
if (image == nil) {
image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];
[self.cachedImages setObject:image forKey:@"thirdimage"];
}
cell.someImage.image = image;
如果您需要以这种方式缓存大量图片,请考虑使用NSCache
代替NSDictionary
来帮助防止缓存过大。