iOS优化UITableViewCell高度计算的一些事儿

2020-01-21 07:40:51于海丽
  • RunLoop即将处理Source
  • RunLoop即将进入休眠状态
  • RunLoop即将从休眠状态被事件唤醒
  • RunLoop退出

    因为“预缓存高度”的任务需要在最无感知的时刻进行,所以应该同时满足:

    • RunLoop 处于“空闲”状态 Mode
    • 当这一次 RunLoop 迭代处理完成了所有事件,马上要休眠时

      使用 CF 的带 block 版本的注册函数可以让代码更简洁:

      
      CFRunLoopRef runLoop = CFRunLoopGetCurrent();
      CFStringRef runLoopMode = kCFRunLoopDefaultMode;
      CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler
      (kCFAllocatorDefault, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity _) {
       // TODO here
      });
      CFRunLoopAddObserver(runLoop, observer, runLoopMode);

      在其中的 TODO 位置,就可以开始任务的收集和分发了,当然,不能忘记适时的移除这个 observer

      分解成多个RunLoop Source任务

      假设列表有 20 个 cell,加载后展示了前 5 个,那么开启估算后 table view 只计算了这 5 个的高度,此时剩下 15 个就是“预缓存”的任务,而我们并不希望这 15 个计算任务在同一个 RunLoop 迭代中同步执行,这样会卡顿 UI,所以应该把它们分别分解到 15 个 RunLoop 迭代中执行,这时就需要手动向 RunLoop 中添加 Source 任务(由应用发起和处理的是 Source 0 任务)
      Foundation 层没对 RunLoopSource 提供直接构建的 API,但是提供了一个间接的、既熟悉又陌生的 API:

      
      - (void)performSelector:(SEL)aSelector
        onThread:(NSThread *)thr
        withObject:(id)arg
        waitUntilDone:(BOOL)wait
         modes:(NSArray *)array;