18

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

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

只是为了澄清一下我所拥有的。我在 iPad 上有砖石/瀑布/pinterest 风格的布局。所以它不仅仅是一个普通的 UITableView。它是一个填满整个屏幕的 UIScrollView,并充满了几个 UIView。每个视图都有一个 150x150 的 UIImageView 和一个 UITableView,并且它还有一些属性标签,使用 Core Text 绘制。所以当你看到屏幕的时候,一眼就可以看到5-8个表格视图,每个单元格又有一个UIImageView,然后每个单元格渲染使用核心文本绘制的属性标签。

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

编辑:

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

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

4

8 回答 8

20

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

  • 简介 - 你说你已经这样做了,太棒了!不幸的是,分析经常被忽视,即使它可以揭示意想不到的问题。在一个应用程序中,我正在使用不同单元格表示日期的日历。起初在单元格之间滚动很慢,这是出乎意料的。我想也许是画了太多的单元格。分析后,我发现它占用了我[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。设备将继续变得更快,旧设备将被淘汰,您的应用程序将逐渐变得更快。

于 2012-08-04T05:24:16.437 回答
7

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

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

于 2012-07-28T19:23:47.720 回答
4

我会做一些称为延迟加载的事情,它不会加载图像,直到它们真正被看到。

这是一个很好的例子: http: //www.cocoacontrols.com/platforms/ios/controls/mhlzytableimages

祝你好运!

于 2012-07-28T19:21:51.363 回答
3

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

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

这确实帮助我在滚动单元格时减少了“口吃”。此外,不要为单元格中的任何内容设置动画 - 这会影响性能。一切都应该完全渲染。

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

编辑:

所以你提供的信息包括 UITableViews 可能是根本问题。所以有两个建议:

1)你能退后一步,弄清楚如何让scrollView成为一个单一的UITableView吗?有了表格的页眉和页脚、部分的页眉和页脚,甚至可以让单元格成为浮动视图,你难道不知道如何重新架构你所拥有的吗?

2)所以你决定不接受建议1。然后,这样做。将 tableview 使用的空间视为容器视图。每当编辑 tableview 时,对其进行图像快照并保留此图像。一旦用户开始滚动,就将 tableViews 换成图像。当 scrollView 停止时,将 UITableView 换回。这当然需要一些微调。事实上,您可能会在滚动期间在表格上覆盖一个不透明的图像快照(这将隐藏它并防止它被要求自行绘制)。

于 2012-07-28T20:49:35.160 回答
1

一般来说,您可以做一些事情来获得更好的表格视图性能:

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: 中完成所有单元格设计,您仍然可以使用 nib,但是:

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

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

3) 如果您使用的是 iOS 5 及更高版本,您可以为特定的单元格标识符注册一个 nib。这样,当您调用 [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),然后再分派到后台线程进行下载。我曾经使用它,但最终我编写了自己的一组类来处理这个问题,而且速度明显更快。

-

只要按照这些,以及其他人在这里写的东西,你就会有像玻璃一样滚动的表格视图:)

于 2012-08-06T22:45:40.303 回答
1

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

于 2012-08-06T17:38:33.887 回答
0

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

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

于 2012-08-06T07:19:08.697 回答
0

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

于 2012-08-06T20:16:21.463 回答