【问题标题】:SKView in UICollectionView terrible performanceUICollectionView 中的 SKView 性能糟糕
【发布时间】:2015-10-19 19:27:43
【问题描述】:

将空的 SKView 添加到 UICollectionView 单元格使得在 iPhone 6 (iOS 9.x) 上滚动几乎不可能。假设集合视图包含 6 个项目,其中前 3 个是可见的,接下来 3 个项目的水平滚动需要 3 秒的抖动。

下面是相关的代码部分:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
    {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(ACDFilterCollectionViewCellConstants.CellIdentifier, forIndexPath: indexPath) as! ACDFilterCollectionViewCell

        let filterType = filters[indexPath.row]

        cell.titleLabel.text = filterType.rawValue

        let skview = SKView(frame: cell.frame)
        cell.filterView.addSubview(skview)

        return cell
    }

我应该怎么做才能在我的 UICollectionViewCells 中使用 SKViews 平滑滚动?

在 iOS 8.x 上,渲染此视图时出现异常:

【问题讨论】:

  • 我在开发者论坛上看到过类似的(或者我可以说是一样的)问题......显然是什么导致了 fps 下降......但实际上,你为什么要这样使用 UICollectionView (混合UIKit 和 SpriteKit)?您确定仅使用 SpriteKit 无法制作所需的一切吗?
  • 我使用 SpriteKit 仅通过自定义着色器绘制 UIBezierPath,然后我将其添加到我的 UIView/UICollectionViewCell。在我开始滚动之前,呈现在单元格或 UICollectionView 之外的其他视图中的形状看起来非常正常。
  • 现在除非我们获得更多信息,否则 Caleb 的答案是您将获得的最佳答案。你到底想达到什么目的?这些可以预渲染并作为 PNG 添加到您的应用中,或者像 Caleb 所说的那样在屏幕外渲染和缓存吗?
  • 我很困惑你说这是一个 iOS 9 问题,但你提到你在 iOS 8 上抛出异常。我认为这在 iOS 8 上也不起作用?
  • @DRHaus 我试图在 iOS 8 和 iOS 9 上使用 SKView 平滑滚动集合视图。出于好奇,我确实尝试过使用图像方法,但它没有用,但那不是什么无论如何我都想要,我希望形状是可动画的。

标签: ios iphone sprite-kit uikit uicollectionview


【解决方案1】:

我不知道具体的答案是什么。性能不佳的原因,但我可以为您提供一些关于如何进行的指示。

首先要做的是分析代码。当您开始滚动时,使用Instruments 找出应用程序在哪里花费的时间最多。当SKViews 出现在屏幕上时设置它们是昂贵的部分吗?还是一遍又一遍地绘制所有这些精灵视图?是不是 in 的 sprite 视图需要很长时间才能绘制?我听说SKShapeNode 可能会拖累性能。如果从SKViews 中删除所有子节点会怎样?

一旦您知道瓶颈在哪里,您就可以决定如何进行。从您的评论看来,您似乎只是在使用SKView 来渲染一些路径,也许一旦绘制它们就不需要它们进行动画处理?如果是这样,也许您可​​以使用单个屏幕外SKView 将您的路径渲染为图像,然后将该图像插入到集合单元格中。人们一直在使用充满图像的集合,而且它们滚动起来很漂亮。

【讨论】:

  • 无论我是使用带着色器的 SKView SKShapeNode,还是只使用空的 SKView,问题都是一样的。我想让我的路径一直处于动画状态,我确实尝试使用 drawViewHierarchyInRect 从 SKView 异步生成和添加图像,但这没有帮助。
【解决方案2】:

我最初的建议很简单:在框架交互和它们之间的关系建立方面降低您对可能发生的事情的期望。

查看 CAShapeLayer,看看它是否可以完成您尝试使用 SKShapeNode 和着色器完成的工作。 CAShapeLayers 有一个“shouldRasterize”功能,然后您可以应用诸如 Core Image 过滤器之类的东西,这可能会让您在不使用 SKViews、SKShapeNode 和 SKShaders 的情况下接近所需的结果。


您面临的问题是人为夸大了对 Apple 较新的 API 和框架中的质量和性能的期望,以及它们相互交互和包容的能力。

这不是你的错。

很久以前,Apple 就掌握了表演技巧和推销技巧。

很长一段时间以来,这些艺术只用于实体产品的发布——人们购买的设备的推销和推广。

在已故伟大的乔布斯先生(愿他安息吧)病重去世的时候,为了更积极地促进软件的快速开发和早期发布到 App Store,正在进行过渡。

其中大部分是针对 Android 和 Google 的战争的一部分。一定有一些共识(可能在现在领先的公司的以供应商为中心的渠道中),让尽可能多的应用进入商店是抵消和/或击败 Android 的一种方式。

为此创建了 iOS 7、UICollectionViews、AutoLayout 和各种其他“美妙”的好东西,旨在消除设计和设计人员对大多数应用程序创建的需求(和担忧)。

这些设施给人的印象是任何事情都可以通过 API 完成,而且几乎不需要考虑设计,甚至不需要考虑技术设计。

因此,开发人员一头扎进框架中,目光炯炯有神,并且对自己的机会或实现他们所设想的任何事情持乐观态度......从他们对 WWDC 视频和其他 Apple 宣传材料的理解来看,框架之间存在差异。

不幸的是,前面提到的推销技巧和表演技巧意味着您认为可能发生的事情实际上仅限于向您展示的文字演示。相互交织的关系和成功的框架的推断和建议可能的潜力就是......可能的未来功能。

除了字面上展示的内容之外,大多数内容都被破坏了,或者以其他方式受到了极大的限制和表现不佳。在某些情况下,所展示的内容随后也会被破坏或无法发布。

因此,如果您花时间想像在 UICollectionViews 中组合 SKViews 之类的事情,并且这种关系应该有效,那么这个假设就是您的问题。

当您开始考虑 SKShapeNodes 和 Shaders 时,情况会变得更糟,这两者在 SceneKit 中都存在已知问题。显然,您发现问题在于 UICollectionViews 中的 SKViews 性能不佳。这是第一个问题。稍后从 SKShapeNodes 和着色器收集性能时会遇到更多问题,然后 SKShapeNode 的不变性问题也会出现在您的动画中。

这不是一个错误的假设,你被引导相信这种框架的模块化是一件事情,并且是 iOS 庞大框架的一个巨大特征。

然而,这一切都还处于早期阶段,并没有被提及。 Sprite Kit 在 iOS 9 中被彻底破坏,你可以在这里阅读更多关于它的许多问题:

https://forums.developer.apple.com/thread/14487

这里:

https://forums.developer.apple.com/thread/20758

这里:

https://forums.developer.apple.com/thread/17463

据我所知,没有关于在 iOS 9 中使用 Scene Kit 的用户遇到问题的原因和/或性质的正式沟通,尽管关于它的许多问题的噪音。

困扰许多人的一个大问题是,任何使用 UIKit 和 SKViews(无论以何种方式它们都可以相互关联)都会在 iOS 9 中导致巨大的性能问题。目前,除了保留这些之外,没有明显的方法可以解决这个问题两个框架分开。

【讨论】:

  • 我想我会试一试 CAShapeLayer。 CIFilters 通常使用 CIImage 作为 inputImage,如果我需要从 CAShapeLayer 创建 CIImage,将其用作 inputImage,然后将该过滤器添加到 CAShapeLayer.filters,这没有任何意义。
  • 是的,我知道你的意思。我们在一个说明性应用程序中为图层制作了实时缩略图,并且必须确保在用户可能与屏幕交互的时候不会发生各种事情,并采取各种技巧来使事件顺序发生在一种保持用户对性能的感知的方式。
  • 这才是真正的诀窍。我们致力于感知性能而不是实际性能,主要是因为不可能实现高性能、真正动态的更新。这就是我降低期望的意思。如果你能做到这一点,那么你就可以开始考虑如何呈现理想体验的 hacky 版本。
  • 只是为了确认,除了我上面描述的以外,没有其他方法可以将 CIFilter 应用于 CAShapeLayer 吗?如何有效地将 CAShapeLayer 转换为 CIImage?
  • CALayers 有一个“内容”,您可以通过这种方式提取/发送/制作 CIImage:stackoverflow.com/questions/9701358/…
【解决方案3】:

iOS 9 与 iOS 8 的一个重大变化是 SpriteKit 和 SceneKit 从 OpenGL 切换到 Metal。我建议您尝试通过将键/值对 PrefersOpenGL/YES 添加到您的 Info.plist 来覆盖该默认值并切换回 OpenGL。见Technical Q&A QA1904, Specifying the renderer for SpriteKit and SceneKit

【讨论】:

  • 谢谢哈尔,它确实提高了性能,但不是很接近我的愿望。
猜你喜欢
  • 1970-01-01
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 2013-02-04
  • 1970-01-01
  • 2015-11-23
相关资源
最近更新 更多