UICollectionView indexPathsForVisibleItems 不更新新的可见单元格

2024-01-09

我有一个 ViewController,里面有一个 CollectionView。加载视图时,可见单元格(9 个单元格)会正确显示。当我向下滚动时,我想通过调用partnerCollectionView的indexPathsForVisibleItems,使用loadImagesForOnscreenRows加载collectionview中的可见项目。但是,当 loadImagesForOnscreenRows 时,indexPathsForVisibleItems 中始终包含前 9 个单元格,即使单元格 10 到 18 应在屏幕上可见。我使用的代码是:

#import "PartnerListViewController.h"
#import "AppDelegate.h"
#import "Partner.h"
#import "ImageLoader.h"
#import "PartnerDetailViewController.h"

@interface PartnerListViewController ()

@end

@implementation PartnerListViewController

@synthesize lblTitle;
@synthesize partnerCollectionView;

@synthesize imageDownloadsInProgress;

@synthesize fetchedResultsController;
@synthesize managedObjectContext;

- (void)viewDidLoad
{
   [super viewDidLoad];
   // Do any additional setup after loading the view.

   AppDelegate * appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
   managedObjectContext = [appDelegate managedObjectContext];
   imageDownloadsInProgress = [NSMutableDictionary dictionary];
   appDelegate = nil;

   [self setupFetchedResultsController];
   [partnerCollectionView reloadData];
}

- (void)didReceiveMemoryWarning
{
   [super didReceiveMemoryWarning];
   // Dispose of any resources that can be recreated.
}

#pragma mark - Collection view data source

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return [[fetchedResultsController sections] count];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
   id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
   return [sectionInfo numberOfObjects];
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"PartnerCell";
   UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];

   Partner *partner = [self.fetchedResultsController objectAtIndexPath:indexPath];

   UIImageView *imageView = (UIImageView *)[cell viewWithTag:100];
   if (!partner.image)
   {
       imageView.image = [UIImage imageNamed:@"annotationMap.png"];
       if (self.partnerCollectionView.dragging == NO && self.partnerCollectionView.decelerating == NO)
       {
           [self startDownload:partner.imageUrl forIndexPath:indexPath];
       }
   } else {
       imageView.image = [UIImage imageWithData:partner.image];
   }

   UILabel *lblTitlePartner = (UILabel *)[cell viewWithTag:101];
   lblTitlePartner.text = partner.title;
   lblTitlePartner.font = [UIFont fontWithName:fontName size:10];

   return cell;
}

#pragma mark - Table cell image support
- (void)startDownload:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath
{
   NSLog(@"startDownload:%ld", (long)indexPath.row);

   ImageLoader *imageLoader = [imageDownloadsInProgress objectForKey:indexPath];
   imageLoader = [[ImageLoader alloc] init];
   imageLoader.urlString = urlString;
   imageLoader.indexPathTableView = indexPath;
   imageLoader.delegate = (id)self;
   [imageDownloadsInProgress setObject:imageLoader forKey:indexPath];
   [imageLoader startDownload];
}

// this method is used in case the user scrolled into a set of cells that don't have their app icons yet
- (void)loadImagesForOnscreenRows
{
   NSArray *visiblePaths = [self.partnerCollectionView indexPathsForVisibleItems];
   NSMutableArray *rowsArray = [NSMutableArray arrayWithCapacity:[visiblePaths count]];
   [visiblePaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
       NSLog(@"loadImagesForOnscreenRows1%@", @(indexPath.item));
       [rowsArray addObject:@(indexPath.item)];
   }];
   for (NSIndexPath *indexPath in visiblePaths)
   {
       NSLog(@"loadImagesForOnscreenRows2:%ld", (long)indexPath.row);

       Partner *item = [self.fetchedResultsController objectAtIndexPath:indexPath];

       if (!item.image) // avoid the app icon download if the app already has an icon
       {
           [self startDownload:item.imageUrl forIndexPath:indexPath];
       }
   }
}

// called by our ImageDownloader when an icon is ready to be displayed
- (void)imageLoaderDidFinishDownloading:(NSIndexPath *)indexPath
{
   NSLog(@"imageLoaderDidFinishDownloading:%ld", (long)indexPath.row);

   ImageLoader *imageLoader = [imageDownloadsInProgress objectForKey:indexPath];
   if (imageLoader != nil)
   {
       // Save the newly loaded image
       Partner *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
       item.image = UIImageJPEGRepresentation(imageLoader.image, 1.0);

       [self performSelectorOnMainThread:@selector(saveItem) withObject:nil waitUntilDone:YES];
       [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
   }
}

- (void)saveItem
{
   [self.managedObjectContext save:nil];
}

- (void)reloadData
{
   [self.partnerCollectionView reloadData];
}

#pragma mark deferred image loading (UIScrollViewDelegate)

// Load images for all onscreen rows when scrolling is finished
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
   if (!decelerate)
{
       [self loadImagesForOnscreenRows];
   }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
   [self loadImagesForOnscreenRows];
}

- (void)setupFetchedResultsController
{
   // 1 - Decide what Entity you want
   NSString *entityName = @"Partner"; // Put your entity name here
   NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);

   // 2 - Request that Entity
   NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];

   // 4 - Sort it if you want
   request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:NO selector:@selector(localizedCaseInsensitiveCompare:)]];
   // 5 - Fetch it
   self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
   NSError *error = nil;
  if (![[self fetchedResultsController] performFetch:&error]) {
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
   }
}

@end

这导致输出:

可见项目的初始显示

2013-09-02 06:45:21.940 [2564:c07] startDownload:0
2013-09-02 06:45:21.943 [2564:c07] imageLoaderDidFinishDownloading:0
2013-09-02 06:45:21.950 [2564:c07] startDownload:1
2013-09-02 06:45:21.951 [2564:c07] imageLoaderDidFinishDownloading:1
2013-09-02 06:45:21.958 [2564:c07] startDownload:2
2013-09-02 06:45:21.959 [2564:c07] imageLoaderDidFinishDownloading:2
2013-09-02 06:45:21.965 [2564:c07] startDownload:3
2013-09-02 06:45:22.063 [2564:c07] imageLoaderDidFinishDownloading:3
2013-09-02 06:45:22.072 [2564:c07] startDownload:4
2013-09-02 06:45:22.073 [2564:c07] imageLoaderDidFinishDownloading:4
2013-09-02 06:45:22.081 [2564:c07] startDownload:5
2013-09-02 06:45:22.082 [2564:c07] imageLoaderDidFinishDownloading:5
2013-09-02 06:45:22.089 [2564:c07] startDownload:6
2013-09-02 06:45:22.090 [2564:c07] imageLoaderDidFinishDownloading:6
2013-09-02 06:45:22.098 [2564:c07] startDownload:7
2013-09-02 06:45:22.099 [2564:c07] imageLoaderDidFinishDownloading:7
2013-09-02 06:45:22.104 [2564:c07] startDownload:8
2013-09-02 06:45:22.163 [2564:c07] imageLoaderDidFinishDownloading:8

滚动到第 10 至 19 项后:

2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:8
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:0
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:1
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:6
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:2
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:3
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:4
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:5
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:7
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:8
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:0
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:1
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:6
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:2
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:3
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:4
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:5
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:7

正如您在滚动后所看到的,项目可见索引路径确实保持不变。有其他人遇到过这个问题或者有解决方案的想法吗?或者我对 CollectionView 的一些原理理解错误?

提前谢谢了! 亲切的问候, 扬


如果您的目标是 iOS 8.0 及更高版本,您应该使用collectionView:willDisplayCell:forItemAtIndexPath:开始下载。如果使用 iOS 7.0,您应该继续使用collectionView:cellForItemAtIndexPath:.

In your imageLoaderDidFinishDownloading:您应该检查有问题的索引路径是否仍然可见。如果是,则检索相应的单元格并更新其图像视图。如果该单元格不可见,则您的工作已完成。呼唤-reloadData对于每个图像完成来说,都需要做大量昂贵的工作,并且如果您的用户当前正在滚动表格并且您重置了其内容,则可能会出现严重的用户体验问题。您也可能正在做UIImageJPEGRepresentation()多次工作,如果您一次执行此工作,将会有助于您的滚动性能imageLoaderDidFinishDownloading:然后缓存它。

由于看起来回调发生在后台线程上,因此请确保您只操作UICollectionView从主线程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UICollectionView indexPathsForVisibleItems 不更新新的可见单元格 的相关文章

随机推荐

  • 错误 D8016:“/ZI”和“/clr”命令行选项不兼容

    我的程序中出现以下错误 error D8016 ZI and clr command line options are incompatible 当我添加以下几行并在配置 gt 常规中启用公共运行时时会发生这种情况 如果我不启用它 则在使用
  • 错误:用户 ''@'localhost' 的访问被拒绝(使用密码:NO)

    我正在尝试使用 MySQL 和 Knex 进行数据库迁移 当我运行命令时knex migrate latest I get ER ACCESS DENIED ERROR Access denied for user localhost us
  • 使用 Node 提供 Vue 应用程序时,构建会导致空 HTML 页面出现语法错误

    我使用 CLI 创建了一个 VueJs 页面 我想在没有安装 Vue CLI 或 Node 的情况下向其他人展示它 就像您通常在浏览器中打开 html 文件一样 我想在构建后打开 index html 文件 当我打开该文件时 我在控制台中看
  • Postgres 中的 Group by 子句中有多个不需要的记录

    我有两张桌子 我将它们连接在一起 然后运行group by条款 问题是我不断收到不需要的数据 client table name company id created at company table name Query SELECT c
  • 使用 VSCode 调试 Celery

    我在用VSCode https code visualstudio com 用于使用 Django 框架进行 Web 开发 调试 Django 没有任何问题 但是当我尝试使用Celery http docs celeryproject or
  • Noob file.copy 问题在复制 .exe 文件 C# 时遇到问题

    我试图将 exe 文件从临时目录复制到桌面 但是当我这样做时 它只是创建一个新的 exe 文件 其中没有数据 大小为 0 KB 我用 txt 文件测试了这个语法 它完全复制了它 只是由于某种原因拒绝复制 exe 文件 我尝试使用string
  • 将颜色声明为常量

    我怎样才能申报Color输入为const像这样 private const Color MyLovedColor Color Blue 这不起作用 因为 Color Blue 是静态的而不是常量 只读对我没有帮助 因为我需要仅 支持 常量的
  • 纬度返回 0,0

    我正在尝试创建一个显示我当前位置的应用程序 我拥有所有必要的许可 我有另一个类名称 GPS 跟踪器来获取我的 GPS 位置 这是我的代码 GPSTracker gpsTracker new GPSTracker this LocationM
  • Nexus 7 上的 Android 4.2:canvas.drawText() 无法正常工作

    我的应用程序面临严重问题 该应用程序发布在 Google Play 上 并且显然在除 gt 4 0 之外的所有 Android 版本上都运行良好 这是我的 Android 4 0 HTC 手机的屏幕截图 这是我在 Nexus 7 Andro
  • 在 Sweetalert 上显示成功消息通知

    我想显示使用 Sweetalert 成功删除数据的消息以及脚本的开头 a href class delete link Delete a JavaScript jQuery document ready function delete li
  • 创建自定义大通知

    我想创建一个包含一些控件的通知 由于文本和控件在默认通知大小 64dp 下都很小 因此我希望它比默认大小更大 可以创建更大的通知 我认为也可以有自定义布局 但我不知道如何 To be more specific the following
  • Clojurescript:错误:无法找到或加载主类 clojure.main

    我按照它安装了 Clojurescript快速入门指南 https github com clojure clojurescript wiki Quick Start 我将 git 存储库拉到 clojurescript CLOJURESC
  • SwiftUI @State var 初始化问题

    我想初始化 a 的值 StateSwiftUI 中的 var 通过init 的方法Struct 因此它可以从准备好的字典中获取正确的文本 以便在 TextField 中进行操作 源代码如下所示 struct StateFromOutside
  • $_GET 。未定义的变量。找不到解决方案[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我遇到了问题并且没有想法 我试图从 URL 获取参数 但 PHP 坚持说该变量未定义 网址是 http localhost tre
  • Twitter Bootstrap 中的响应式表处理

    当表格的宽度超过跨度的宽度时 就像这个页面 http jsfiddle net rcHdC http jsfiddle net rcHdC 您将看到表格的内容超出了span 解决这种情况的最佳方法是什么 引导程序3 http blog ge
  • 如何在 AngularJS 指令中的元素上绑定滚动事件

    如何在 AngularJS 指令中的元素上绑定滚动事件 我在 window 上绑定滚动 但现在我需要将其更改为此类 body wrapper angular element document queryselector body wrapp
  • 如何将 pandas 数据框逐行写入 CSV 文件,一次一行?

    我有一个大约 100 万个地址的列表 以及一个查找它们的纬度和经度的函数 由于某些记录的格式不正确 或出于任何原因 有时该函数无法返回某些地址的纬度和经度 这将导致 for 循环中断 因此 对于成功检索到纬度和经度的每个地址 我想将其写入输
  • firebase db:具有 Kotlin 委托属性的模型

    我正在使用 Kotlin 对象来处理我的 Firebase 数据库模型 如上所述在指南中 https firebase google com docs database android read and write basic write
  • 使用 JavaScript 滚动页面

    我在用着Ender js http ender no de 我试图让页面滚动到特定位置 我认为我在这里做错了什么 但页面甚至没有移动 理想情况下 我希望使用动画事件 但 emile 不接受scrollTop 作为参数 任何帮助表示赞赏 do
  • UICollectionView indexPathsForVisibleItems 不更新新的可见单元格

    我有一个 ViewController 里面有一个 CollectionView 加载视图时 可见单元格 9 个单元格 会正确显示 当我向下滚动时 我想通过调用partnerCollectionView的indexPathsForVisib