UICollectionView单元格图像错误
UICollectionView cell image error
我正在开发一个带有示例 UICollectionView 的应用程序,该应用程序应加载从 Internet 下载的一堆图标。所以基本上服务器检索一个列表,其中包含 JSON 文件中每个图标的 URL,应用程序对其进行解析,然后每个单元格下载相应的图像。
这种方法的问题似乎是,如果用户在图片下载时开始滚动,用户将开始以错误的顺序看到图片!这就像 UICollectionView 正在尝试 'help me' 并且它呈现了它在错误位置的内容!
我看过很多关于此的帖子,我尝试了他们的大部分建议,但到目前为止运气不佳。有人见过这样的东西吗?
这是 cellForItemAtIndexPath 的样子:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PeqImage *image = [self.responseIcons objectAtIndex:indexPath.row];
PeqCustomCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"PeqCustomCell" forIndexPath:indexPath];
cell.peqImage = image;
cell.imageName = [NSString stringWithFormat:@"%@.png",image.assetId];
NSString *theImageUrl = [NSString stringWithFormat:@"http://www.XXXX.com/pb/images/uncompressed/%ld.png",(long)indexPath.row];
[cell downloadImage:[NSURL URLWithString:theImageUrl]];
return cell;
}
这是下载算法的样子(使用 UIImageView+AFNetworking):
- (void) downloadImageWithUrl:(NSURL*) url completion:(PeqCustomCellCompletionBlock)completionBlock
{UIImage *placeholder = [UIImage imageNamed:@"placeholder"];
NSURLRequest *jpegURLRequest = [NSURLRequest requestWithURL:url];
self.imageUrl = url.absoluteString;
[self.imageView setImageWithURLRequest:jpegURLRequest
placeholderImage:placeholder
success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image) {
image = [self normalizeImage:image];
completionBlock(image);
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
NSLog(@"Error downloading image from network");
}];
}
问题是每次隐藏并再次显示单元格时,您都需要重新下载图像。更好的方法是提前下载所有数据,然后使用它填充collectionView。
我怀疑线程是罪魁祸首。所有 UI 代码都必须从主线程调用。现在使用了这么多块,很容易不小心从后台线程进行 UI 调用。当你这样做时,各种奇怪的事情开始出现。
我会尝试将您的最后一段代码更改为此,以便在主线程上分派图像调用。我刚刚添加了一个 dispatch_async() 函数。
self.imageUrl = url.absoluteString;
[self.imageView setImageWithURLRequest:jpegURLRequest
placeholderImage:placeholder
success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image){
dispatch_async(dispatch_get_main_queue(), ^{
image = [self normalizeImage:image];
completionBlock(image);
});
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
NSLog(@"Error downloading image from network");
}];
你应该使用 SDWebImage library 来处理类似的东西,
#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 sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
cell.textLabel.text = @"My Text";
return cell;
}
这是您可以将其用于您的 collection view
!!
的 tableview 示例
此库缓存图像以实现可重用性。
如果你想实现或了解native way
这些东西,那么你可以参考Loading Images in UICollectionViewCell: Naive to the Clever.
问题是集合视图单元格被重复使用。所以你告诉一个单元格在屏幕上下载一个特定的图像,然后它离开屏幕并在集合视图需要另一个单元格时被重用,然后你告诉同一个单元格下载另一个图像。最后下载完成的图片是最后显示的图片。
在您的下载完成块中,在设置 image = [self normalizeImage:image];
之前,您应该检查请求 url 是否与当前的 self.imageUrl
匹配。如果不是,则图像来自旧请求,您不想在单元格中显示它。
我正在开发一个带有示例 UICollectionView 的应用程序,该应用程序应加载从 Internet 下载的一堆图标。所以基本上服务器检索一个列表,其中包含 JSON 文件中每个图标的 URL,应用程序对其进行解析,然后每个单元格下载相应的图像。
这种方法的问题似乎是,如果用户在图片下载时开始滚动,用户将开始以错误的顺序看到图片!这就像 UICollectionView 正在尝试 'help me' 并且它呈现了它在错误位置的内容!
我看过很多关于此的帖子,我尝试了他们的大部分建议,但到目前为止运气不佳。有人见过这样的东西吗?
这是 cellForItemAtIndexPath 的样子:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PeqImage *image = [self.responseIcons objectAtIndex:indexPath.row];
PeqCustomCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"PeqCustomCell" forIndexPath:indexPath];
cell.peqImage = image;
cell.imageName = [NSString stringWithFormat:@"%@.png",image.assetId];
NSString *theImageUrl = [NSString stringWithFormat:@"http://www.XXXX.com/pb/images/uncompressed/%ld.png",(long)indexPath.row];
[cell downloadImage:[NSURL URLWithString:theImageUrl]];
return cell;
}
这是下载算法的样子(使用 UIImageView+AFNetworking):
- (void) downloadImageWithUrl:(NSURL*) url completion:(PeqCustomCellCompletionBlock)completionBlock
{UIImage *placeholder = [UIImage imageNamed:@"placeholder"];
NSURLRequest *jpegURLRequest = [NSURLRequest requestWithURL:url];
self.imageUrl = url.absoluteString;
[self.imageView setImageWithURLRequest:jpegURLRequest
placeholderImage:placeholder
success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image) {
image = [self normalizeImage:image];
completionBlock(image);
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
NSLog(@"Error downloading image from network");
}];
}
问题是每次隐藏并再次显示单元格时,您都需要重新下载图像。更好的方法是提前下载所有数据,然后使用它填充collectionView。
我怀疑线程是罪魁祸首。所有 UI 代码都必须从主线程调用。现在使用了这么多块,很容易不小心从后台线程进行 UI 调用。当你这样做时,各种奇怪的事情开始出现。
我会尝试将您的最后一段代码更改为此,以便在主线程上分派图像调用。我刚刚添加了一个 dispatch_async() 函数。
self.imageUrl = url.absoluteString;
[self.imageView setImageWithURLRequest:jpegURLRequest
placeholderImage:placeholder
success:^(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image){
dispatch_async(dispatch_get_main_queue(), ^{
image = [self normalizeImage:image];
completionBlock(image);
});
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
NSLog(@"Error downloading image from network");
}];
你应该使用 SDWebImage library 来处理类似的东西,
#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 sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
cell.textLabel.text = @"My Text";
return cell;
}
这是您可以将其用于您的 collection view
!!
此库缓存图像以实现可重用性。
如果你想实现或了解native way
这些东西,那么你可以参考Loading Images in UICollectionViewCell: Naive to the Clever.
问题是集合视图单元格被重复使用。所以你告诉一个单元格在屏幕上下载一个特定的图像,然后它离开屏幕并在集合视图需要另一个单元格时被重用,然后你告诉同一个单元格下载另一个图像。最后下载完成的图片是最后显示的图片。
在您的下载完成块中,在设置 image = [self normalizeImage:image];
之前,您应该检查请求 url 是否与当前的 self.imageUrl
匹配。如果不是,则图像来自旧请求,您不想在单元格中显示它。