[英]Images in UITableView keep re-loading and wrong images flash while scrolling in swift
[英]Images in UITableView keep re-loading and wrong images flash while scrolling
我创建了一个UITableView,它填充来自URL请求的每个单元格。 我已经使用'dispatch_queue'来防止UItableView冻结。 出于某种原因,当我滚动浏览UITableView时,图像会闪烁并消失,并在错误的单元格中填充一秒钟,直到修复自身。 这是我的代码。 我正在使用restkit提取提要
customCell.customCellTextLabel.text = [NSString stringWithFormat:@"%@",feedO.title];
NSString *string = [NSString stringWithFormat:@"%@",feedO.body];
NSURL *urlString;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
}
}
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
return customCell;
您添加的代码缺少一行。
customCell.customCellImageView.image = nil;
customCell.customCellTextLabel.text = [NSString stringWithFormat:@"%@",feedO.title];
NSString *string = [NSString stringWithFormat:@"%@",feedO.body];
NSURL *urlString;
customCell.customCellImageView.image =nil;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
}
}
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
return customCell;
原因是UITableView
正在重用创建的单元格。 因此,它首先创建了CustomCell
类的10个。
储存格0
单元格1
...
单元格9
通过创建这10个单元,它将启动10个异步调用以获取图像。
块0->单元0
块1->单元1
...
块9->单元9
如果在所有10个下载完成之前不滚动,则此方法会正常工作。
但是,一旦您开始滚动, UITableView
将开始重新使用创建的单元格并启动新的下载。
因此,它首先可以重用单元0并创建块10->单元0。
如果在选择单元0进行重用时块0尚未完成,那么您现在将有两个块想要将其图像放置在同一单元上。 导致以下两种情况:
这就是导致“闪烁”的原因。
然后想象一下在几秒钟内滚动浏览数千个单元格:)
解
您需要能够取消排队的块,以便重新使用您的单元格。
我会使用例如SDWebImage或FastImageCache 。
你怎么说 您将图像捕获在另一个线程中,以防止冻结。 在tableView中,单元被重用,而在一个后台线程中捕获新照片时,在主线程中,返回具有前一张照片的单元。 在代码中,我对其进行了修复并提供了更好的解释:
customCell.customCellTextLabel.text = [NSString stringWithFormat:@“%@”,feedO.title];
NSString *string = [NSString stringWithFormat:@"%@",feedO.body];
NSURL *urlString;
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:string options:0 range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matches) {
if ([match resultType] == NSTextCheckingTypeLink) {
urlString = [match URL];
NSLog(@"found Body URL: %@ and title %@", urlString,feedO.title);
}
}
// Here you need, at least quit the previous imagen, is better if you implement
// and activity indicator (here start), and also you should implement some imagen cache.
customCell.customCellImageView.image = nil;
// Apart from here, go to another thread.
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
// this operation is slowly that return a cell, this happens after [1]
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
//If you implement and activity indicator stop here.
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
// [1] the cell is returned before the image is ready.
return customCell;
以上答案是正确的。 但无需下载单元格中的图像即可。 您可以在符合您要求的viewWillAppear或ViewDidLoad中进行表加载之前下载图像。
每次滚动表格时,图像都会再次下载。 为了防止这种情况,我更希望您从缓存中获取图像并直接在imageview中进行设置。 因此根据您的代码。 如果从0索引滚动到10,则单元格将下载所有10个单元格的图像。 之后,如果再次滚动10到索引0。 然后图像将再次下载。
您可以使用( https://github.com/rs/SDWebImage )下载图像异步。 它非常容易和快速。
我更喜欢这个库,因为它将处理您的缓存。 只需写下面的代码
#import "UIImageView+WebCache.h"
// in cellForRowAtIndexPath.
[customCell.customCellImageView sd_setImageWithURL: [NSURL URLWithString:urlString]];
删除下面的代码。
dispatch_queue_t imageQueue = dispatch_queue_create("imageDownloader",nil);
dispatch_async(imageQueue, ^{
NSData *data = [[NSData alloc] initWithContentsOfURL:urlString];
dispatch_async(dispatch_get_main_queue(), ^{
customCell.customCellImageView.image = [UIImage imageWithData: data];
});
});
也许这会对您有所帮助。
您应该考虑使用此库SDWebImage,有关此类问题,请参见https://github.com/rs/SDWebImage 。 它非常轻松地处理远程图像的异步下载和缓存。
最简单的安装通过使用CocoaPods完成
CocoaPods( http://cocoapods.org )是Objective-C的依赖项管理器,它可以自动化并简化在项目中使用第三方库的过程。 有关更多详细信息,请参见“入门”部分。
在您的Podfile中使用
platform :ios, '6.1'
pod 'SDWebImage', '~>3.6'
安装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"]];
cell.textLabel.text = @"My Text";
return cell;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.