PrefetchRowsAt will not work if there are no lines left

I am using the new prefetchDataSource of UITableView (can also be applied to UICollectionView . The task that I have is the following:

  • I am implementing a func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) , which works very well.

  • I use an array that starts with 15 elements. Therefore, array.count , which is equal to 15, will be initially returned in array.count .

  • I want the prefetchRowsAt function to tell me when we exit the lines so that I retrieve new data from my own source, add this data to an array , and then reloadData() , which in turn will increase numberOfRowsInSection .

  • The problem is that prefetchRowsAt will not go beyond line 15 because it is limited to the numberOfRowsInSection I numberOfRowsInSection . So basically, I'm stuck. Basically, when I'm on line 5, I want him to tell me to prefetch line 16.

One solution that I tried and worked would be to increase the numberOfRowsInSection to say 100, and then place the placeholder cells while I get the new data. But the scrollbar will look too small, since it is expected that there will be 100 elements, so the UX will not be so pleasant.

Perhaps the template that I use in step 3 is incorrect (add reloadData to the array as well)? Or can you think of another cleaner solution to the problem?

Thanks in advance!

+6
source share
2 answers

I think I understood my point: your class has a mutableArray to save your Cell data model. Each time, a resource return request is 15.

  • the first time: the amount of data received is 15, you want to pre-query the following resources from the server when the user scrolls to the 5th cell of the index path. After receiving reqeust, your mutableArray counter is 30

  • the second time: you want to pre-get the following resources from the server when the user scrolls to the 25th cell of the index pair. After receiving reqeust, your mutableArray counter is 45

  • permanently make a request next time resouces while the user is sliding around the screen

OK, You do not need to use prefetchDataSource (it was used only for iOS 10), and not using dataSource. .

Of course, if you run your application only in iOS 10, you can make a net-request for metadata (e.g. pre-caching images) in Cell by implementing the prefetch method. If not, you can use cellForRowAtIndexPath (tableView) or cellForItemAtIndexPath (collectionView )

  • For UITableView

    Tableview: cellForRowAtIndexPath:

  • For UICollectionView

    CollectionView: cellForItemAtIndexPath:

Futher, I do not suggest you use scrollViewDidScroll ,

Raising the height of a cell usually depends on changing the data if it is more expensive.

your code may like this code below: (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; } 

If you do not need your application to be compatible with iOS10 below, you can put the prelaod code in the prefetch method.

BTW: If you think my answer works, please feel free to accept it :)


#Updates : on how to reload: you can control the array using KVO, for example:

 [self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 

and implement this method

 -(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
source

I think you should asynchronously load your new data and just insert new lines: func insert​Rows(at:​with:​) instead of reloadData (you insert data, not reload it).

You can start loading new data as soon as the prefetch method gets to the last line (or earlier). After downloading it, you can call begin​Updates() , update your array, insert new lines, and finally end​Updates() .

See the docs for more details: Batch insert, delete, and reload rows and sections

0
source

Source: https://habr.com/ru/post/1015561/


All Articles