带有图像的 UITableView 在滚动时会暂时显示错误的图像
UITableView with images display wrong image for a moment while scrolling
我有一个 UITableView
,它有很多行,每行只有一张图片。为了防止延迟,我使用了下面的代码。但是现在,当我滚动时,它会暂时显示前几行的照片,然后自行更正。如何解决这个问题?
- (void)loadImageNamed:(NSString *)name {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// Determine path to image depending on scale of device's screen,
// fallback to 1x if 2x is not available
NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"jpg"];
NSString *pathToImage = pathTo1xImage;
UIImage *uiImage = nil;
if (pathToImage) {
// Load the image
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithFilename([pathToImage fileSystemRepresentation]);
CGImageRef image = CGImageCreateWithJPEGDataProvider(imageDataProvider, NULL, NO, kCGRenderingIntentDefault);
// Create a bitmap context from the image's specifications
// (Note: We need to specify kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
// because PNGs are optimized by Xcode this way.)
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetWidth(image) * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
// Draw the image into the bitmap context
CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
// Extract the decompressed image
CGImageRef decompressedImage = CGBitmapContextCreateImage(bitmapContext);
// Create a UIImage
uiImage = [[UIImage alloc] initWithCGImage:decompressedImage];
// Release everything
CGImageRelease(decompressedImage);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
CGImageRelease(image);
CGDataProviderRelease(imageDataProvider);
}
// Configure the UI with pre-decompressed UIImage
dispatch_async(dispatch_get_main_queue(), ^{
self.categoryImageLabel.image = uiImage;
});
});
}
在您的自定义单元格中写入:
- (void)prepareForReuse {
[super prepareForReuse];
self.uiImage.image = nil;
}
您的旧图像正在被 tableview 重复使用,这意味着如果 imageview 有图像,当视图回收它时它会是相同的,所以您必须将它设为 nil 或替换为占位符图像(如果有)。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = CustomUITableViewCell
cell.imageview.image = nil
// load your image
}
或者在您的自定义单元格调用中准备重用,每次单元格被 table 重用时都会被调用:
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil // or place holder image
}
其他答案会告诉您做什么,但不会告诉您为什么。
将单元格想象成您必须在医生办公室候诊室填写的表格。想象一下,办公室重复使用这些表格,每个患者在填写信息之前必须擦除表格上的所有数据。
如果您没有任何过敏症,您可能会想跳过过敏部分,因为它们不适用于您。但是,如果最后一个人有过敏症,并且您没有删除他们的答案,他们的答案仍会显示在表格上。
同样,当您将回收的单元格出列时,您必须清除所有字段,即使是那些不适用于您的字段。您应该将图像设置为 nil 或它们的起始占位符值。
请注意,如果您异步加载数据,您仍应首先将字段重置为其默认值,因为旧值将在异步加载完成之前显示。这就是你的情况。
您可以在 cellForRowIndexPath
或 prepareForReuse
中将图像设置为 nil/placeholder,但您需要在其中一个位置重置它,否则您会看到剩余的图片直到新图片完成加载。
尽管接受的答案有效,但这不是推荐的方式。
根据 Apple's documentation,您应该只重置 与内容 无关的单元格属性,例如 alpha、编辑和选择状态。
因此,处理此问题的最佳方法是在 cell(for row:atIndexPath:)
中设置一个默认图像,这样它可以处理您拥有图像的两种情况,并在图像是默认图像时求助于默认图像不可用,这将在您快速滚动时执行。它不会加载图像,并且在单元格的重用行为中它将选择默认图像。
我有一个 UITableView
,它有很多行,每行只有一张图片。为了防止延迟,我使用了下面的代码。但是现在,当我滚动时,它会暂时显示前几行的照片,然后自行更正。如何解决这个问题?
- (void)loadImageNamed:(NSString *)name {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// Determine path to image depending on scale of device's screen,
// fallback to 1x if 2x is not available
NSString *pathTo1xImage = [[NSBundle mainBundle] pathForResource:name ofType:@"jpg"];
NSString *pathToImage = pathTo1xImage;
UIImage *uiImage = nil;
if (pathToImage) {
// Load the image
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithFilename([pathToImage fileSystemRepresentation]);
CGImageRef image = CGImageCreateWithJPEGDataProvider(imageDataProvider, NULL, NO, kCGRenderingIntentDefault);
// Create a bitmap context from the image's specifications
// (Note: We need to specify kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
// because PNGs are optimized by Xcode this way.)
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBitsPerComponent(image), CGImageGetWidth(image) * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
// Draw the image into the bitmap context
CGContextDrawImage(bitmapContext, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
// Extract the decompressed image
CGImageRef decompressedImage = CGBitmapContextCreateImage(bitmapContext);
// Create a UIImage
uiImage = [[UIImage alloc] initWithCGImage:decompressedImage];
// Release everything
CGImageRelease(decompressedImage);
CGContextRelease(bitmapContext);
CGColorSpaceRelease(colorSpace);
CGImageRelease(image);
CGDataProviderRelease(imageDataProvider);
}
// Configure the UI with pre-decompressed UIImage
dispatch_async(dispatch_get_main_queue(), ^{
self.categoryImageLabel.image = uiImage;
});
});
}
在您的自定义单元格中写入:
- (void)prepareForReuse {
[super prepareForReuse];
self.uiImage.image = nil;
}
您的旧图像正在被 tableview 重复使用,这意味着如果 imageview 有图像,当视图回收它时它会是相同的,所以您必须将它设为 nil 或替换为占位符图像(如果有)。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = CustomUITableViewCell
cell.imageview.image = nil
// load your image
}
或者在您的自定义单元格调用中准备重用,每次单元格被 table 重用时都会被调用:
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil // or place holder image
}
其他答案会告诉您做什么,但不会告诉您为什么。
将单元格想象成您必须在医生办公室候诊室填写的表格。想象一下,办公室重复使用这些表格,每个患者在填写信息之前必须擦除表格上的所有数据。
如果您没有任何过敏症,您可能会想跳过过敏部分,因为它们不适用于您。但是,如果最后一个人有过敏症,并且您没有删除他们的答案,他们的答案仍会显示在表格上。
同样,当您将回收的单元格出列时,您必须清除所有字段,即使是那些不适用于您的字段。您应该将图像设置为 nil 或它们的起始占位符值。
请注意,如果您异步加载数据,您仍应首先将字段重置为其默认值,因为旧值将在异步加载完成之前显示。这就是你的情况。
您可以在 cellForRowIndexPath
或 prepareForReuse
中将图像设置为 nil/placeholder,但您需要在其中一个位置重置它,否则您会看到剩余的图片直到新图片完成加载。
尽管接受的答案有效,但这不是推荐的方式。
根据 Apple's documentation,您应该只重置 与内容 无关的单元格属性,例如 alpha、编辑和选择状态。
因此,处理此问题的最佳方法是在 cell(for row:atIndexPath:)
中设置一个默认图像,这样它可以处理您拥有图像的两种情况,并在图像是默认图像时求助于默认图像不可用,这将在您快速滚动时执行。它不会加载图像,并且在单元格的重用行为中它将选择默认图像。