如果没有剩余行,PrefetchRowsAt 将不起作用
Posted
技术标签:
【中文标题】如果没有剩余行,PrefetchRowsAt 将不起作用【英文标题】:PrefetchRowsAt won't work if no rows left 【发布时间】:2017-03-07 10:40:04 【问题描述】:我正在使用UITableView
的新prefetchDataSource
(也可以应用于UICollectionView
。我遇到的问题如下:
我正在实施func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
,它工作得很好。
我使用的是array
,它以 15 个元素开头。所以numberOfRowsInSection
最初会返回array.count
,即 15。
我想要的是 prefetchRowsAt
函数告诉我我们何时用完了行,以便我从自己的源获取新数据,将这些数据附加到 array
然后reloadData()
,这反过来会增加numberOfRowsInSection
。
prefetchRowsAt
不会超出第15 行,因为它受到我指定的numberOfRowsInSection
的限制。所以基本上,我被卡住了。基本上,当我在第 5 行时,我希望它告诉我开始预取第 16 行。
我尝试并工作的一个解决方案是将numberOfRowsInSection
的计数增加到100,然后在我获取新数据时放置占位符单元格。但是滚动条看起来太小了,因为它预计有 100 个项目,所以 UX 不会那么好。
也许我在第 3 步中使用的模式是错误的(附加到数组并重新加载数据)?或者您能想出另一种更清洁的解决方案吗?
提前致谢!
【问题讨论】:
我不确定您的问题出在哪里。当prefetchRowsAt:
函数中的 indexPath.row 接近特定偏移量时,您应该开始新的提取。就像indexPath.row+10 >= array.count
一样,您应该开始获取。
@Lefteris 是的,这就是我现在使用'cellForRowAt:'所做的。我想使用“prefetchRowsAt:”来避免这样做,如果可能的话,也是为了让省长依赖于单元格的大小,而不是随机常数“10”。
对于单元格的大小,您可以使用scrollViewDidScroll:
委托方法,看看您距离可滚动内容的末尾还有多远,并据此开始预取。 UITableViewDataSourcePrefetching
协议用于下载已添加到 TableView 数据源的单元格的数据(如预缓存图像),而不是用于分页....See the documentation here
@Guy 数组中的数据来自哪里?
@Zonker.in.Geneva 网络调用为主,有时会缓存在设备中。
【参考方案1】:
我想我已经理解了你的意思:你的类有一个 mutableArray 来存储你要显示的 Cell 的数据模型。每次返回的资源请求数为15。
第一次:获取的数据数为 15,当用户滚动到第 5 个 indexpath 单元格时,您希望预先从服务器请求下一个资源。 得到请求后,你 mutableArray 的计数是 30
第二次:当用户滚动到第 25 个 indexpath 单元格时,您希望从服务器预先获取下一个资源。 得到请求后,你的 mutableArray 的计数是 45
只要用户滑动屏幕,就永远请求下次资源
好的,不需要使用prefetchDataSource(只有iOS 10可用),而是可以使用dataSource。。
当然,如果你只在 ios 10 上运行你的应用程序,你可以通过实现 prefetch 方法在 Cell 中对元数据(如预缓存图像)进行网络请求 .如果没有,您可以使用 cellForRowAtIndexPath(tableView) 或 cellForItemAtIndexPath(collectionView)
对于 UITableView
tableView:cellForRowAtIndexPath:
对于 UICollectionView
collectionView:cellForItemAtIndexPath:
另外,我不建议你使用 scrollViewDidScroll,
因为单元格的高度通常会随着数据的变化而变化 ,如果它会更贵。
您的代码可以像下面这样的代码:(UICollectionView)
@interface YourCollectionView()
@property (nonatomic, strong) SDWebImagePrefetcher *imagePrefetcher;
@end
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
// Check current indexPath
NSInteger distance = self.array.count - indexPath.row-1;
if (distance <= 10)
[self loadingMoreData];
// Preload the ten image into the cache, if you need your app to be compatible with iOS10 below.
NSMutableArray <NSURL*> *URLsArray = [[NSMutableArray alloc] init];
for (NSInteger i = 1; i <= 10; i++)
NSInteger y = currentLastIndexRow + i;
if (y > self.array.count-1)
break;
YourModel *model = self.array[indexPath.item];
ImageModel *image = model.image;
[URLsArray addObject:[NSURL URLWithString:image.httpsURL]];
[self.imagePrefetcher prefetchURLs:URLsArray];
YourCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
// setting your Cell
[cell setNeedsLayout];
return cell;
如果您的应用不需要兼容iOS10以下,可以将prelaod代码放到prefetch方法中。
顺便说一句:如果您认为我的回答有效,请不要犹豫采纳它:)
#Updates:关于如何重新加载:您可以使用KVO监控阵列, 喜欢:
[self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
并实现这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
if([keyPath isEqualToString:@"array"])
if(!change) return;
id oldC = [change objectForKey:NSKeyValueChangeOldKey];
id newC = [change objectForKey:NSKeyValueChangeNewKey];
UICollectionView *cv = selfWeak.collectionView;
// changes is non-nil, so we just need to update
[cv performBatchUpdates:^
// delete reload insert..
completion:^(BOOL finished)
// do somethind , like scrollToItemAtIndexPath
];
【讨论】:
【参考方案2】:我认为您应该开始异步加载新数据并插入新行:func insertRows(at:with:)
而不是 reloadData
(您是在插入数据,而不是重新加载它)。
您可以在预取方法到达最后一行(或之前)时立即开始加载新数据。加载后,您可以调用beginUpdates()
,更新您的数组,插入新行,最后是endUpdates()
。
在文档中查看更多信息:Batch Insertion, Deletion, and Reloading of Rows and Sections
【讨论】:
【参考方案3】:嗯,PrefetchDelegate 的工作方式有点不同。
你需要告诉 tableview 你的系统总共有多少行。
所以基本上你需要传递将在 cellForRowAtIndexPath 中显示的对象表视图的总数。
完成此操作后,prefetchRowsAt 将开始调用,并让您知道它将显示哪一行,您应该在那里应用您的 API 调用逻辑。
如果您需要更多说明,请告诉我。
【讨论】:
以上是关于如果没有剩余行,PrefetchRowsAt 将不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如果我只使用没有 hostPort 的 containerPort,AWS eb 的 docker 设置将不起作用。(多容器 Docker)