如果没有行,PrefetchRowsAt将无法工作

时间:2017-03-07 10:40:05

标签: ios swift uitableview uicollectionview prefetch

我正在使用prefetchDataSource的新UITableView(也可以应用于UICollectionView。我遇到的问题如下:

  1. 我正在实施func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]),效果很好。

  2. 我使用的是array,以15个元素开头。因此,在numberOfRowsInSection中,最初会返回array.count,即15。

  3. 我想要的是prefetchRowsAt函数告诉我当我们的行已经用完时,以便从我自己的源中获取新数据,将这些数据附加到{{1 }然后array,这将反过来增加reloadData()

  4. 问题是numberOfRowsInSection不会超出第15行,因为它受到我指定的prefetchRowsAt的限制。基本上,我卡住了。基本上,当我在第5行时,我希望它告诉我开始预取第16行。
  5. 我尝试和工作的一个解决方案是将numberOfRowsInSection的数量增加到100,然后在我获取新数据时放置占位符单元格。但滚动条看起来太小,因为它预计有100个项目,所以UX不会那么好。

    也许我在步骤3中使用的模式是错误的(追加到数组和reloadData)?或者您能想到另一个更清洁的问题解决方案吗?

    提前致谢!

3 个答案:

答案 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 insert​Rows(at:​with:​)而不是reloadData(您正在插入数据,而不是重新加载它)。

一旦预取方法到达最后一行(或之前),您就可以开始加载新数据。加载后,您可以调用begin​Updates(),更新数组,插入新行,最后end​Updates()

在文档中查看更多内容:Batch Insertion, Deletion, and Reloading of Rows and Sections

答案 2 :(得分:-1)

嗯,PrefetchDelegate的工作方式有些不同。

您需要告知tableview系统中总共有多少行。

因此,基本上,您需要传递对象表视图的总数将显示在 cellForRowAtIndexPath 中。

完成此操作后, prefetchRowsAt 将开始调用,并让您知道它将显示在哪一行,并应在其中应用API调用逻辑。

让我知道是否需要更多说明。