我正在使用prefetchDataSource
的新UITableView
(也可以应用于UICollectionView
。我遇到的问题如下:
我正在实施func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
,效果很好。
我使用的是array
,以15个元素开头。因此,在numberOfRowsInSection
中,最初会返回array.count
,即15。
我想要的是prefetchRowsAt
函数告诉我当我们的行已经用完时,以便从我自己的源中获取新数据,将这些数据附加到{{1 }然后array
,这将反过来增加reloadData()
。
numberOfRowsInSection
不会超出第15行,因为它受到我指定的prefetchRowsAt
的限制。基本上,我卡住了。基本上,当我在第5行时,我希望它告诉我开始预取第16行。我尝试和工作的一个解决方案是将numberOfRowsInSection
的数量增加到100,然后在我获取新数据时放置占位符单元格。但滚动条看起来太小,因为它预计有100个项目,所以UX不会那么好。
也许我在步骤3中使用的模式是错误的(追加到数组和reloadData)?或者您能想到另一个更清洁的问题解决方案吗?
提前致谢!
答案 0 :(得分:3)
我想我理解了你的意思:你的班级有一个mutableArray来存储你的Cell的数据模型。每次,资源请求的计数都是15。
第一次:获取的数据计数为15,当用户滚动到第5个indexpath单元时,您希望从服务器预先生成下一个资源的请求。 获得reqeust之后,你的mutableArray的计数是30
:当用户滚动到第25个indexpath单元格时,您希望从服务器预先获取下一个资源。 获得reqeust之后,你的mutableArray计数是45
将永久请求下次资源
好的,没有必要使用prefetchDataSource(它只能使用iOS 10),而不是使用dataSource。。
当然,如果你只在iOS 10中运行你的应用程序,你可以通过实现预取方法在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代码添加到预取方法中。
顺便说一句:如果您认为我的答案有效,请不要犹豫,采纳它:)#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
}];
}
}
答案 1 :(得分:0)
我认为您应该开始异步加载新数据并只插入新行:func insertRows(at:with:)
而不是reloadData
(您正在插入数据,而不是重新加载它)。
一旦预取方法到达最后一行(或之前),您就可以开始加载新数据。加载后,您可以调用beginUpdates()
,更新数组,插入新行,最后endUpdates()
。
在文档中查看更多内容:Batch Insertion, Deletion, and Reloading of Rows and Sections
答案 2 :(得分:-1)
嗯,PrefetchDelegate的工作方式有些不同。
您需要告知tableview系统中总共有多少行。
因此,基本上,您需要传递对象表视图的总数将显示在 cellForRowAtIndexPath 中。
完成此操作后, prefetchRowsAt 将开始调用,并让您知道它将显示在哪一行,并应在其中应用API调用逻辑。
让我知道是否需要更多说明。