I am using the new prefetchDataSource
of UITableView
(also can be applied to UICollectionView
. The problem that I am having is the following:
I am implementing func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
which works pretty fine.
I am using an array
which starts with 15 elements. So in numberOfRowsInSection
will initially return array.count
which is 15.
What I want is for the prefetchRowsAt
function to tell me when we're runing out of the rows, so that I fetch new data from my own source, append these data to the array
and then reloadData()
, which will in turn increase the numberOfRowsInSection
.
prefetchRowsAt
won't go beyond row 15 because it is limited by the numberOfRowsInSection
that I specified. So basically, I get stuck. Basically, when I am at row 5, I want it to tell me to start prefetching row 16.One solution that I tried and worked would be to increase the count of numberOfRowsInSection
to say 100, and then put placeholder cells while I am fetching the new data. But the scrolling bar will look too small as it is expecting that there is 100 items, so the UX won't be that nice.
Maybe the pattern that I use in step 3 is wrong (append to array and reloadData)? Or Can you think of another cleaner solution to the problem?
Thanks in advance!
I think I has understood your meaning: Your class have an mutableArray to store your Cell's data model to shown. Everytime, the count of resource request back is 15.
at first time: the count of data got is 15, you want to pre-making the request of next resources from server when user scroll to 5th indexpath cell . After get reqeust, your mutableArray's count is 30
at second time: you want to pre-get next resources from server when user scroll to 25th indexpath cell . After get reqeust, your mutableArray's count is 45
forever making request for next time resouces ,as long as user slides the screen
OK, It's not necessary that using prefetchDataSource(it is only usable iOS 10), rather than you can using dataSource. .
Of course,if you only run your app in iOS 10 , you can making net-request for meta data(like pre-caching images) in Cell by implement prefetch method . If not, you can use cellForRowAtIndexPath(tableView) or cellForItemAtIndexPath(collectionView)
For UITableView
tableView:cellForRowAtIndexPath:
For UICollectionView
collectionView:cellForItemAtIndexPath:
Futher, I'm not suggest you using scrollViewDidScroll,
Becuase the height of the cell usually varies with the change of data ,if it will be more expensive.
your code can 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 app to be compatible with iOS10 below,you can put prelaod code to prefetch method.
BTW: If you think my answer working, please do not hesitate to adopt it : )
#Updates: About how to reload: You can monitor array by using KVO, like:
[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
}];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With