什么是可接受的滚动 FPS,以及提高性能的技巧是什么



我在许多WWDC视频中看到,您希望尽可能接近60.0 FPS,以获得更好的平滑滚动体验。我有一个UIScrolLView,可以一次加载图像和几个表格视图。目前我得到 30 FPS。这是推荐 FPS 的一半。只是想知道你们通常会为加载图像和其他繁重内容/渲染内容的表格视图/滚动视图获得什么 FPS。

优化 FPS 还有其他技巧吗?在过去的一周里,我一直在使用时间分析器、分配和核心动画工具来启动乐器,以尽可能多地进行优化。

只是为了澄清一下我所拥有的。我在iPad上有一个砖石/瀑布/pinterest风格的布局。所以它不仅仅是一个普通的UITableView。这是一个UIScrollView,填满了整个屏幕,并充满了几个UIView。此视图中的每一个都有一个 150x150 的 UIImageView 和一个 UITableView,并且它还具有一些使用核心文本绘制的属性标签。因此,当您看到屏幕时,您可以一目了然地看到 5-8 个表格视图,每个单元格再次具有 UIImageView,然后每个单元格呈现使用核心文本绘制的属性标签。

所以你可以想象这有多深和复杂。这不仅仅是带有 UIImageView 的常规表视图。我知道如何在带有UIImage的iPhone中仅使用一个UITableView获得60 FPS。这个概念是异步加载图像,而不是尽可能多地阻塞主线程。

编辑:

似乎这里的问题是我视图中的UITableView..当我从UIView中删除它时,我得到了非常流畅的滚动。

上传了一个示例项目,它是我所拥有的更简单的版本,但它清楚地显示了问题。链接在这里

许多因素都会影响渲染性能,以下是您可以检查的一些项目:

  • 个人资料 - 你说你已经这样做了,干得太好了!不幸的是,分析经常被忽视,即使它可以揭示意外的问题。在一个应用程序中,我正在处理一个日历,其中包含代表日期的不同单元格。起初在单元格之间滚动很慢,这是出乎意料的。我想也许是画了太多的单元格。分析后,我发现[NSCalender currentCalender]占用了 85% 的 CPU 时间!修复后,一切都滚动得很好!

  • 图像 - 大图像在CoreGraphics中增加了大量负载。滚动尤其需要大量的绘制操作来移动它们。一个技巧是尽可能少地缩放设备上的图像,这使得CoreGraphics的工作变得更加容易。如果图像的大小是显示它的视图的两倍,请在视图中显示它之前调整 UIImage 的大小。iOS 设备处理 PNG 的最佳方式。它们在编译时由工具(pngcrush(压缩,iOS有特殊的硬件来渲染它们。

编辑:JPG可能是照片的更好选择。 iOS设备也有专用的JPG解码器。

  • 自定义绘图 - 如果可能,请减少您执行的自定义 CGContext 绘图的数量。 许多自定义绘图会对动画速度产生负面影响。如果可能的话,我会考虑使用图像而不是复杂的自定义绘图。

  • 剔除 - 只画你需要的东西。 UITableView自动卸载和加载出现的单元格,因此这是为您完成的,但任何自定义 CGContext 绘图都应仅在该部分可见时才执行。根据我的经验,自动视图阴影也可能非常慢。

  • 重用 - 在UITableView上使用重用标识符,这将允许UITableView重用单元格对象,而不是在滚动时重新分配 - 看看这个问题的答案。还要重用UIImages,而不是为同一文件分配多个。 imageNamed会自动缓存图像,但imageFromContents文件不会。

  • 创建自己的网格视图类 - 可以创建自己的网格视图类,该类剔除隐藏在屏幕外的子视图视图,并使用延迟内容加载进行滚动。通过编写自定义解决方案,您可以完全控制流程并创建针对使用上下文优化的设计。对于大多数用例,您将很难构建比Apple标准更好的东西,但是我已经看到在特定情况下完成了它。

  • 最后的手段 - 减小违规视图的大小(改进过滤(,将内容分成多个页面,缩小图像大小,删除性能不佳的旧设备。在牺牲大部分东西之前,我会满足于 30 FPS。设备将继续变得更快,旧设备将被淘汰,您的应用程序将逐渐变得更快。

我用我的UITableViewController接近 60 fps,其中表格包含大约 2000 个单元格,每个单元格从网络中提取图像。诀窍是根据需要延迟加载图像。这个来自苹果的例子代码非常有用。

一般的想法是通过不阻塞主线程来保持 UI 响应。在另一个线程上执行下载和其他耗时的任务。

我会做一些叫做延迟加载的事情,它会在实际看到图像之前不会加载图像。

这里有一个关于如何做到这一点的很好的例子:http://www.cocoacontrols.com/platforms/ios/controls/mhlazytableimages

祝你好运!

我所做的是使用NSCache。我创建了一个小类,其属性符合 NSCache 数据协议(这真的很容易做到(。所以我所做的是在主表中的每个单元格和各种值得缓存的东西之间创建一个关系:NSA归因字符串、图像等 - 实际上是任何需要工作才能创建的东西。我不预加载它,但你可以。

当系统要求您在表视图旁边提供单元格时,请在缓存中查找主要对象。如果在那里,请拉动您需要的所有对象。如果缓存没有对象,则以旧方式获取数据,但在完成之前,也要将其保存在缓存中。

这确实帮助我减少了滚动单元格时的"卡顿"。另外,不要对单元格中的任何内容进行动画处理 - 这会降低性能。一切都应该完全渲染。

要记住的另一件事 - 确保可以设置为不透明的视图将其属性设置为 YES。这肯定有助于系统渲染单元格(包括背景视图,如果您使用一个(。

编辑:

因此,您提供的信息包含 UITableViews 可能是根本问题。所以有两个建议:

1(你能退后一步,弄清楚如何使滚动视图成为单个UITableView吗?有了表格页眉和页脚,以及节页眉和页脚,甚至基本上使单元格成为浮动视图的能力,您不能弄清楚如何重新构建您拥有的内容吗?

2(所以你决定不建议1。然后,执行此操作。将表视图使用的空间视为容器视图。每当编辑表视图时,请为其拍摄图像快照并保留此图像。一旦用户开始滚动,就将表视图换成图像。当滚动视图停止时,将 UITableView 换回去。这当然需要一些微调。事实上,在滚动过程中,您可能会在表格上覆盖一个不透明的图像快照(这将隐藏它并防止它被要求自己绘制(。

人眼看到的速度约为 60 FPS,所以这就是推荐它的原因,但 30 FPS 也会显得非常流畅,尤其是当普通用户正在查看它时,而不是你试图找到尽可能多的修复。这显然取决于滚动的速度,如果帧与帧之间的差异是几个像素的移动,30 FPS 就可以了,但更快的移动需要更高的 FPS 才能看起来平滑

通常,您可以执行一些操作来获得更好的表视图性能:

1(切换到Loren Brichter绘制UITableViewCell的方法(因为缺乏更好的链接:http://www.therefinedgeek.com.au/index.php/2010/12/21/fast-scrolling-uitableview-updates-for-ios-4-2/(

基本上,他的所有代码所做的就是将所有单元格内容渲染为一个不透明的UIView,UITableView(和CoreGraphics(可以非常快速地将其加载到UITableViewCell上。

如果您不想在drawRect:中进行所有单元格设计,您仍然可以使用笔尖,但是:

  • 确保每个子视图都标记为不透明
  • 没有任何透明/半透明子视图
  • 没有任何带有 alpha 通道的图像 != 1.0f。

2(不要让UIImageView做任何缩放来显示你的图像,给它一个正确大小的UIImage。

3( 如果您使用的是 iOS 5 及更高版本,则可以为特定单元格标识符注册笔尖。这样,当您调用 [tableView dequeueReusableCellWithIdentifier:] 时,可以保证获得一个单元格。单元格分配更快(根据Apple的说法(,并且您可以编写更少的代码:

- (void)viewDidLoad {
    UINib *nib = [UINib nibWithNibName:@"MyCell" bundle:nil];
    [self.tableView registerNib:nib forCellReuseIdentifier:@"MyCellIdentifier"];
}
// ...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"MyCellIdentifier";
    MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    // Commented out code is no longer needed
    //if (cell == nil) {
    //    cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    //}
    // setup cell
    return cell;
}

4( 显示从网络下载的图像

  • 显示默认图像(下载真实图像时要查看的内容(
  • 在单独的线程上开始下载(提示:使用 GCD 的 dispatch_async(((
  • 当图像进入时,缓存它(提示:NSCache(,并将其显示在单元格上
      在主线程上
    • 下载/缓存所有图像;在主线程上唯一应该做的就是设置图像(记住UI代码必须在主线程上!(

您可能需要编写支持异步的 UIImageView(或使用现有库(。

远离 EGOImageView,即使它具有异步下载功能,在调度到后台线程进行下载之前,它会在主线程上进行缓存查找(恰好在磁盘上,因此这意味着昂贵的磁盘 IO(。我曾经使用它,但我最终编写了自己的一组类来处理这个问题,而且它的速度要快得多。

-

只需遵循这些内容,以及其他人在这里写的东西,您就会立即获得像玻璃一样滚动的表格视图:)

你想要 60fps,但 30 fps 实际上看起来并不太糟糕。 但是我会尝试达到 60fps 以便在滚动时获得更流畅的外观。

有许多性能改进的可能性,各种教程也展示了这些可能性

虽然 60 FPS 是理想的,但像 Halo 这样的游戏在 30 FPS 下运行得非常漂亮。《光环》中的战场混乱可能比大多数列表更令人惊讶,快速移动,甚至是像你这样的复杂列表!

最新更新