RGScrollLayoutCache 1.1.0

RGScrollLayoutCache 1.1.0

Renge维护。



 
依赖项
RGRunTime>= 0
RGObserver>= 0
 

  • 作者
  • RengeRenge

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秒在布局方法中

#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次布局

load_in_main_sync

  • 33次布局等待后台线程完成

hit for async

  • 后台线程中进行了551次布局

load in cahce queue

  • 0次取消布局

cancel in cache queue