如何停止在 CollectionView 中自动重新加载和刷新图像 iOS
How to stop Automatic reloading and refreshing of images in CollectionView iOS
我正在尝试将 URL 中的一些图像显示到我的 collection 视图中。但是当我尝试这样做时,我的图像显示在 collection 视图中,但它们随机地保持刷新和重新加载。此外,当我尝试滚动 collection 视图时,它会再次重新加载我不想要的整个数据。我只想向用户显示类似预览的图像。
下面是我从 URL 获取图像并将其显示在 collection 视图上的代码。
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
__block NSString *filename;
for(NSDictionary *item in [jsonSD objectForKey:@"Data"]) {
for (int i=0; i<=[[item objectForKey:@"Count"]integerValue]; i++) {
filename=[NSString stringWithFormat:@"http://..URL../media/content/%@%@%d_1.png",_getstring,[item objectForKey:@"subcategory_id"],i];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:filename];
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, NSData *data) {
if (succeeded) {
iv.image = [[UIImage alloc] initWithData:data];
}
}];
});
}
}
return cell;
}
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, NSData *data))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
completionBlock(YES, data);
} else {
completionBlock(NO, nil);
}
}];
}
这里 'iv' 是我的 imageView,我在 collection 视图的单元格上显示图像。
我尝试搜索相关内容,但我对上述问题一无所知。
请帮帮我。感谢任何帮助。
我不明白你想做什么,当你滚动你的集合视图时,它总是会获取图像数据,因为重用机制。您可以在 viedDidLoad() 方法中获取图像数据,在完成图像数据获取后重新加载您的集合视图。
看来这里有两个问题:
第一个问题是:
cellForItemAtIndexPath
每次单元格 出现 时都会被调用,这意味着如果您正在滚动,那么 downloadImageWithURL
每次单元格都会被调用出现在屏幕上。
第二个问题似乎是使用 for (int i=0; i<=[[item objectForKey:@"Count"]integerValue]; i++)
为每个单元格加载多个图像
这个循环好像下载了多张图片,然后依次将它们设置在同一个单元格上?
第一个问题的一些解决方案:
- 如果您只需要显示几个项目,请加载
viewDidLoad
中的所有图像并在每次下载其中一个图像时更新数据源。
- 下载每个单元格的图像后,将其添加到数组中。每次加载单元格时,检查数组是否包含该单元格的图像并使用它而不是下载新的。
第二题:
不确定循环的目的是什么,您是否希望循环中的每个图像都显示在它自己的集合视图单元格中?
更新:
这里有一个简单的示例,可以向您展示代码的外观。我不知道 jsonSD
或您代码的其他部分包含什么,但它应该给您正确的想法:
@interface TestCollectionViewController () {
NSMutableArray *datasource;
NSDictionary *jsonSD;
}
@end
@implementation TestCollectionViewController
static NSString *const reuseIdentifier = @"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
// We want to load the data from all cells as soon as the view loads, instead of loading the data as the cells scroll.
// Lazy loading cells will require a more advanced implementation
[self loadDatasource];
}
- (void)loadDatasource {
for (NSDictionary *item in [jsonSD objectForKey:@"Data"]) {
// Fill the datasource with null objects which match the total number of objects you want to display
datasource = [NSMutableArray arrayWithCapacity:[[item objectForKey:@"Count"] integerValue]];
for (int i = 0; i <= [[item objectForKey:@"Count"] integerValue]; i++) {
[datasource addObject:[NSNull null]];
}
// Reload the collectionview now so that the empty cells will be displayed with no image.
[self.collectionView reloadData];
// Load each image individually and replace the corresponding NSNull in the datasource.
for (int i = 0; i <= [[item objectForKey:@"Count"] integerValue]; i++) {
NSString *filename = [NSString stringWithFormat:@"http://..URL../media/content/%@%@%d_1.png", _getstring, [item objectForKey:@"subcategory_id"], i];
NSURL *url = [NSURL URLWithString:filename];
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, NSData *data) {
if (succeeded) {
[datasource replaceObjectAtIndex:i withObject:[UIImage imageWithData:data]];
// Reload the collectionview after each item has downloaded so the image gets displayed in the cell.
[self.collectionView reloadData];
}
}];
}
}
}
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, NSData *data))completionBlock {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
completionBlock(YES, data);
} else {
completionBlock(NO, nil);
}
}];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
// Only displaying one section
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return datasource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
if ([datasource objectAtIndex:indexPath.row] == [NSNull null]) {
// Display a default image here
} else {
// Image has been loaded, display it in the imageview
iv.image = [datasource objectAtIndex:indexPath.row];
}
return cell;
}
更新二:
上面的答案效率不高,如果您有数百个项目,则效果不会太好。对于更可靠的实现,我建议使用像 SDWebImage 这样的库来为您处理它。然后你可以做一些简单的事情:
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {... completion code here ...}];
我正在尝试将 URL 中的一些图像显示到我的 collection 视图中。但是当我尝试这样做时,我的图像显示在 collection 视图中,但它们随机地保持刷新和重新加载。此外,当我尝试滚动 collection 视图时,它会再次重新加载我不想要的整个数据。我只想向用户显示类似预览的图像。 下面是我从 URL 获取图像并将其显示在 collection 视图上的代码。
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
__block NSString *filename;
for(NSDictionary *item in [jsonSD objectForKey:@"Data"]) {
for (int i=0; i<=[[item objectForKey:@"Count"]integerValue]; i++) {
filename=[NSString stringWithFormat:@"http://..URL../media/content/%@%@%d_1.png",_getstring,[item objectForKey:@"subcategory_id"],i];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:filename];
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, NSData *data) {
if (succeeded) {
iv.image = [[UIImage alloc] initWithData:data];
}
}];
});
}
}
return cell;
}
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, NSData *data))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
completionBlock(YES, data);
} else {
completionBlock(NO, nil);
}
}];
}
这里 'iv' 是我的 imageView,我在 collection 视图的单元格上显示图像。 我尝试搜索相关内容,但我对上述问题一无所知。
请帮帮我。感谢任何帮助。
我不明白你想做什么,当你滚动你的集合视图时,它总是会获取图像数据,因为重用机制。您可以在 viedDidLoad() 方法中获取图像数据,在完成图像数据获取后重新加载您的集合视图。
看来这里有两个问题:
第一个问题是:
cellForItemAtIndexPath
每次单元格 出现 时都会被调用,这意味着如果您正在滚动,那么 downloadImageWithURL
每次单元格都会被调用出现在屏幕上。
第二个问题似乎是使用 for (int i=0; i<=[[item objectForKey:@"Count"]integerValue]; i++)
这个循环好像下载了多张图片,然后依次将它们设置在同一个单元格上?
第一个问题的一些解决方案:
- 如果您只需要显示几个项目,请加载
viewDidLoad
中的所有图像并在每次下载其中一个图像时更新数据源。 - 下载每个单元格的图像后,将其添加到数组中。每次加载单元格时,检查数组是否包含该单元格的图像并使用它而不是下载新的。
第二题:
不确定循环的目的是什么,您是否希望循环中的每个图像都显示在它自己的集合视图单元格中?
更新:
这里有一个简单的示例,可以向您展示代码的外观。我不知道 jsonSD
或您代码的其他部分包含什么,但它应该给您正确的想法:
@interface TestCollectionViewController () {
NSMutableArray *datasource;
NSDictionary *jsonSD;
}
@end
@implementation TestCollectionViewController
static NSString *const reuseIdentifier = @"Cell";
- (void)viewDidLoad {
[super viewDidLoad];
// We want to load the data from all cells as soon as the view loads, instead of loading the data as the cells scroll.
// Lazy loading cells will require a more advanced implementation
[self loadDatasource];
}
- (void)loadDatasource {
for (NSDictionary *item in [jsonSD objectForKey:@"Data"]) {
// Fill the datasource with null objects which match the total number of objects you want to display
datasource = [NSMutableArray arrayWithCapacity:[[item objectForKey:@"Count"] integerValue]];
for (int i = 0; i <= [[item objectForKey:@"Count"] integerValue]; i++) {
[datasource addObject:[NSNull null]];
}
// Reload the collectionview now so that the empty cells will be displayed with no image.
[self.collectionView reloadData];
// Load each image individually and replace the corresponding NSNull in the datasource.
for (int i = 0; i <= [[item objectForKey:@"Count"] integerValue]; i++) {
NSString *filename = [NSString stringWithFormat:@"http://..URL../media/content/%@%@%d_1.png", _getstring, [item objectForKey:@"subcategory_id"], i];
NSURL *url = [NSURL URLWithString:filename];
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, NSData *data) {
if (succeeded) {
[datasource replaceObjectAtIndex:i withObject:[UIImage imageWithData:data]];
// Reload the collectionview after each item has downloaded so the image gets displayed in the cell.
[self.collectionView reloadData];
}
}];
}
}
}
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, NSData *data))completionBlock {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
completionBlock(YES, data);
} else {
completionBlock(NO, nil);
}
}];
}
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
// Only displaying one section
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return datasource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell
if ([datasource objectAtIndex:indexPath.row] == [NSNull null]) {
// Display a default image here
} else {
// Image has been loaded, display it in the imageview
iv.image = [datasource objectAtIndex:indexPath.row];
}
return cell;
}
更新二:
上面的答案效率不高,如果您有数百个项目,则效果不会太好。对于更可靠的实现,我建议使用像 SDWebImage 这样的库来为您处理它。然后你可以做一些简单的事情:
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {... completion code here ...}];