我创建了一个UITableView,它从URL请求中填充每个单元格。我使用'dispatch_queue'来阻止UItableView冻结。出于某种原因,当我滚动浏览UITableView时,图像闪烁并消失并填充错误的单元格一秒钟直到自我修复。这是我的代码。我正在使用restkit
来提取FeedcustomCell.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;
答案 0 :(得分:0)
你的代码缺少一行,我添加了。
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;
答案 1 :(得分:0)
原因是UITableView
正在重复使用创建的单元格。
首先,它创建了10个CustomCell
类。
细胞0
单元1
...
细胞9
通过创建这10个单元格,它将启动10个异步调用来获取图像。
块0 - >单元格0
块1 - >单元1
...
方框9 - >细胞9
如果您不滚动直到所有10次下载完成,这将正常工作。
但是一旦你开始滚动,UITableView
将开始重用创建的单元格并启动新的下载。
首先,它可以重用Cell 0并创建块10 - > Cell 0。
如果在选择单元格0以供重复使用时块0未完成,则现在将有两个块想要将它们的图像放在同一单元格上。 导致以下两种情况:
这是导致"闪烁"。
的原因然后想象在几秒钟内滚动1000个单元格:)
<强>解决方案强>
您需要能够取消已重复使用的单元格的排队块。
我会使用例如SDWebImage或FastImageCache。
答案 2 :(得分:0)
你怎么说。你在另一个线程中捕获图像,以防止冻结。并且在tableView中,单元格被重用,而在一个后台线程中,您正在捕获新照片,在主线程中返回包含上一张照片的单元格。 在代码中我修复了它并提供了更好的解释:
customCell.customCellTextLabel.text = [NSString stringWithFormat:@&#34;%@&#34;,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;
答案 3 :(得分:0)
以上答案是正确的。但不需要在单元格中下载图像行。您可以在viewWillAppear或ViewDidLoad中发生表加载之前下载图像,这符合您的要求。
答案 4 :(得分:0)
每次重新下载图像时滚动表格。为了防止这种情况,我更喜欢你从缓存中获取图像并直接在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];
});
});
也许这会对你有帮助。
答案 5 :(得分:0)
您应该考虑使用此库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;
}