RGScrollLayoutCache
在后台线程中预加载UITableView或UICollectionView的布局
- RGScrollLayoutCache是UIScrollview的一个分类
- RGScrollLayoutCache可以帮助UITableView或UICollectionView预加载布局并将其保存到缓存中
- 自动缓存加载机制参考使用Photos框架的示例应用
安装
通过添加以下代码到Podfile中,使用CocoaPods进行安装
pod 'RGScrollLayoutCache'
用法
- 设置缓存代理
[self.tableView rg_setLayoutCacheDelegate:self];
- 启用自动缓存
self.tableView.rg_autoCache = YES;
- 否则请使用自定义缓存
RGScrollLayoutCache可以与UITableViewDataSourcePrefetching合作。然而,测试后这种方式的表现并不令人满意。
- (void)tableView:(UITableView *)tableView prefetchRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
[tableView rg_startCachingLayoutForIndexPaths:indexPaths];
}
- (void)tableView:(UITableView *)tableView cancelPrefetchingForRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
[tableView rg_stopCachingLayoutForIndexPaths:indexPaths];
}
- RGLayoutCacheDelegate
// Do layout at this delegate.
- (CGSize)scrollView:(UIScrollView *)scrollView sizeForRowAtIndexPath:(NSIndexPath *)indexPath isMainThread:(BOOL)isMainThread {
// safe-get size whether in the main thread or in the background thread
CGSize size = scrollView.rg_nowFrame.size;
// get data source. ⚠️realm database need get a new instance in other thread.
RLMRealm *realm = nil
if (!isMainThread) {
realm = self.caCheRealm;
[realm refresh];
} else {
realm = self.realm;
}
// do layout with size and data source
return size;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [tableView rg_layoutCacheSizeAtIndexPath:indexPath].height;
}
- 当数据源发生变化或scrollView大小发生变化时清除缓存
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGRect last = self.tableView.rg_lastFrame;
// width is related to layout in this example.
if (self.tableView.frame.size.width != last.size.width) {
[self.tableView rg_updateLastFrame];
[self.tableView rg_clearlayoutCache];
[self.tableView reloadData];
}
}
[self.tableView rg_clearlayoutCacheAtIndexPaths:indexPaths];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
- 启用日志
[UIScrollView rg_setCacheLogEnable:YES];
测试报告
此演示生成了1000行随机文本并休眠0.01秒在布局方法中
-
演示GIF
-
布局代码
#pragma mark - RGLayoutCacheDelegate
- (CGSize)scrollView:(UIScrollView *)scrollView sizeForRowAtIndexPath:(NSIndexPath *)indexPath isMainThread:(BOOL)isMainThread {
[NSThread sleepForTimeInterval:0.01];
CGSize size = scrollView.rg_nowFrame.size;
size.width -= (52 + 20 + 20 + 20);
size.height = CGFLOAT_MAX;
NSString *string = self.fakeData[indexPath.row];
size = [string
boundingRectWithSize:size
options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13.f]}
context:nil].size;
size.height = MAX(60, size.height);
size.height += 40;
return size;
}
- 主线程中进行了25次布局
- 33次布局等待后台线程完成
- 后台线程中进行了551次布局
- 0次取消布局