AnyView 对 SwiftUI 性能的影响

news2024/10/6 12:32:40

在这里插入图片描述

文章目录

    • 前言
    • 测试设置
    • 动画卡顿
    • 浏览数据
      • 没有 AnyView
    • 有 AnyView
    • 在浏览数据时修改
      • 没有 AnyView
    • 有 AnyView
    • 分析结果
    • 总结

前言

AnyView 是一种类型擦除的视图,对于 SwiftUI 容器中包含的异构视图非常方便。在这些情况下,你不需要指定视图层次结构中所有视图的具体类型。通过这种方式,你可以避免使用泛型,从而简化你的代码。

然而,这可能会带来性能损失。如果是 AnyView(基本上是一个包装类型),SwiftUI 将很难确定视图的身份和结构,并且它将重新绘制整个视图,这并不是真正高效的。你可以在这个出色的 WWDC 演讲中找到有关 SwiftUI 差异机制的更多细节。

Apple 也多次提到,我们应该避免在 ForEach 中使用 AnyView,称其可能会导致性能问题。一个可能发生的情况是无尽的不同视图列表,呈现不同类型的数据(例如聊天、活动动态等)。在本文中,我将使用 Stream 的 SwiftUI 聊天 SDK 进行一些测量,使用其默认的基于泛型的实现,并将其与使用 AnyView 的修改后的实现进行比较。

测试设置

关于测试设置的几点说明:

  • 所有测试和测量都在 iPhone 11 Pro Max 上进行。
  • 为保持一致性,在所有测试中都使用相同的数据集和用户。
  • 测试会执行多次。
  • 正在测试的列表具有不同类型的数据(例如图像、视频、GIF、文本等)。
  • 在测试不同实现时执行相同的操作(例如,在内容上滚动三次)。
  • 数据以每页 25 个项目的形式获取。
  • 我们将使用动画卡顿仪器配置文件以及这个开源 FPS 计数器。

动画卡顿仪器配置文件

动画卡顿

苹果建议使用动画卡顿作为衡量应用性能的指标。卡顿基本上是指在屏幕上显示的帧比预期晚的帧。卡顿时间越长,出现的故障和挂起就越明显,从而造成用户体验不佳。例如,如果你有 100 毫秒的卡顿,这意味着此帧显示晚于预期的 100 毫秒,从而使用户可以看到挂起。卡顿可以出现在提交阶段或渲染阶段。

为了提高我们应用的性能,我们需要将这些动画卡顿降到最低(或者更好地摆脱它们)。

我还将展示与 FPS(每秒帧数)的比较,因为它通常是开发人员更熟悉的度量标准之一。当使用 FPS 作为度量标准时,重要的是指定最大帧速率(在这种情况下为 60),并在应用程序没有活动时丢弃值。

浏览数据

首先,让我们看看在浏览内容时不同的实现会表现如何。在这个测试中,我们将通过整个消息列表三次滚动。

没有 AnyView

下面是没有泛型实现的动画卡顿记录。

如你所见,有几个动画卡顿,其中 2 个是橙色的,这意味着卡顿持续时间超过了可接受的延迟时间 33 毫秒。因此,在这 2 种情况下,将会丢失一帧。这 2 个卡顿发生在加载新消息并将其附加到消息列表时。在加载消息时进行任何后续滚动,不会影响性能。

在此测试期间,FPS 值的平均值约为每秒 59 帧。滚动是流畅且响应迅速的。

有 AnyView

接下来,让我们做同样的测试,同时使用 AnyView 包装器。以下是动画卡顿仪器配置文件中的结果。

你可以在此示例中看到一些更多的橙色。有更多的动画卡顿超过了可接受的延迟时间 33 毫秒。这导致在执行测试时在仪器和视觉上都出现一些可见的卡顿。

此外,当你再次浏览列表时,性能不会改善(甚至变得更糟)。这是有道理的,因为 SwiftUI 不知道它已经显示过此视图一次(因为它隐藏在 AnyView 下)。因此,它会再次绘制它,同时还可能缓存(但不使用)该视图的旧版本。

此测试中的平均 FPS 约为每秒 55 帧,你可能会注意到在滚动时出现一些可见的故障,尽管情况并不那么糟糕。

在浏览数据时修改

我们可以进行的另一个测试是性能测试 - 向列表发送大量内容并强制更新视图(例如,响应消息),同时我们也浏览数据。这将在较短的时间间隔内触发视图的多次重绘。

没有 AnyView

在没有 AnyView 包装器的情况下进行测试产生了与常规滚动测试相似的结果(58-59 FPS)。这也是预期的,因为 SwiftUI 知道视图的标识和结构。当需要更新视图时,仅对其进行更改(例如,向视图添加另一个反应)。

有 AnyView

当我们在这种情况下使用 AnyView 时,事情就变得有趣了 - 在短时间内对屏幕上的视图进行频繁更新。

在此场景中,有几个可见的卡顿和挂起,当我们频繁响应消息时,FPS 降至 50 以下。由于在几秒钟内强制重绘视图多次,帧丢失在这里更加明显。由于 SwiftUI 不知道这个视图是什么,我假设它每次都会从头开始重绘。其中一些视图相当昂贵(例如 GIF),因此重新绘制可能是一项相当昂贵的操作。

通过使用 AnyView,效果类似于将 id 修饰符的值设置为 UUID() - 这将在发生更改时始终更新视图项目。

分析结果

测试/实现没有 AnyView(FPS)有 AnyView(FPS)性能退化
浏览数据595510%
在浏览数据时修改595016.5%

这些数字相当依赖于设置,因此不应该被视为铁板钉钉的结果,而只是一个指示。

仅浏览数据时,如果你将视图包装在 AnyView 中,则会比不包装时慢大约 10%。如果你在浏览数据时更改数据,则此差异将增加到约 17%,而且这些故障在这里更加明显。

为了更好地理解结果,我们需要深入了解 SwiftUI 的工作原理。在这个关于 SwiftUI 性能的 WWDC 会话中,来自 SwiftUI 团队的 Raj 讨论了列表或表需要提前知道所有标识符。只有在内容解析为恒定数量的行时,才能高效地收集它们而无需访问所有内容。如果使用条件检查或 AnyView,将无法确定行数,并且必须提前创建所有视图,这会影响性能。

因此,请尽量避免这样的代码:

ForEach(someData) { someElement inif someCondition {
    SomeView(data: someElement)}
}

以及像这样的代码:

ForEach(someData) { someElement in
    AnyView(SomeView(data: someElement))
}

最后一段代码类似于我们使用 AnyView 进行测试的方式。这意味着,当列表发生更改时,我们实际上重新创建了整个列表。这也解释了为什么 AnyView 实现随着时间的推移变慢 - 每次重绘时都需要从头开始创建更多内容。

总结

总而言之,在这些情景中(包含异构视图的可滚动列表),最好为容器中的不同视图使用具体类型。这可能听起来更复杂一些,但实际上你可以使其更简单,而不必过多地处理泛型。

然而,这并不意味着使用 AnyView 总是会以这种方式影响性能。例如,如果你有一个菜单,作为几个异构元素的列表,在点击时显示不同的导航目标,并且决定将这些视图包装为 AnyView,我的测量结果表明与使用其他方法相比,性能没有区别。

在这篇文章中,使用 AnyView 与使用 if-else 语句的不同类型的测试显示出没有显着差异。使用 if-else 导致视图标识丢失,就像 AnyView 一样,因此在这里没有性能差异是可以预期的。

这也取决于实现的方式 - 你的数据模型,将状态传递到哪里,哪些更新可能会导致视图重绘等等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1890651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据】—美国交通事故分析(2016 年 2 月至 2020 年 12 月)

引言 在当今快速发展的数字时代,大数据已成为我们理解世界、做出决策的重要工具。特别是在交通安全领域,大数据分析能够揭示事故模式、识别风险因素,并帮助制定预防措施,从而挽救生命。本文将深入探讨2016年2月至2020年12月期间&…

西南交通大学【算法分析与设计实验5】

有障碍物的不同路径数量 实验目的 (1)理解动态规划算法的求解过程。 (2)分析动态规划算法的时间复杂度,比较动态规划算法与其他算法的效率差异。 (3)学会如何利用动态规划算法求解具体问题&…

汇聚荣拼多多电商哪些热词比较受关注?

汇聚荣拼多多电商哪些热词比较受关注?在探讨拼多多电商平台的热点关键词时,我们首先得明确,这个平台因其独特的商业模式和市场定位,吸引了大量消费者的目光。拼多多通过“拼团”购物的方式迅速崛起,成为电商行业的一个重要力量。…

5% 消耗,6 倍性能:揭秘新一代 iLogtail SPL 日志处理引擎与 Logstash 的 PK

作者:阿柄 引言 在当今数据驱动的时代,日志收集和处理工具对于保障系统稳定性和优化运维效率至关重要。随着企业数据量的不断增加和系统架构的日益复杂,传统日志处理工具面临着性能、灵活性和易用性等多方面的挑战。Logstash 作为一款广受欢…

qt6 通过http查询天气的实现

步骤如下: cmakelist 当中,增加如下配置 引入包 访问远端api 解析返回的数据 cmakelist 当中,增加如下配置,作用是引入Network库。 引入包 3、访问远端api void Form1::on_pushButton_clicked() {//根据URL(http://t.weather.…

GoLand 2024 for Mac GO语言集成开发工具环境

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件(适合自己的M芯片版或Intel芯片版),将其从左侧拖入右侧文件夹中,等待安装完毕2、应用程序显示软件图标,表示安装成功3、打开访达,点击【文…

Flask 数据创建时出错

当我们在使用 Flask 创建数据时遇到错误,可能有多种原因,包括代码错误、数据库配置问题或依赖项错误。具体情况我会总结成一篇文章记录下,主要是归类总结一些常见的解决方法和调试步骤,帮助大家解决问题: 1、问题背景 …

013、MongoDB常用操作命令与高级特性深度解析

目录 MongoDB常用操作命令与高级特性深度解析 1. 数据库操作的深入探讨 1.1 数据库管理 1.1.1 数据库统计信息 1.1.2 数据库修复 1.1.3 数据库用户管理 1.2 数据库事务 2. 集合操作的高级特性 2.1 固定集合(Capped Collections) 2.2 集合验证(Schema Validation) 2.…

如何批量创建、提取和重命名文件夹!!!

你是否还在一个一个手动创建文件名! 你是否还在一个一个手动提取文件名! 你是否还在一个一个手动修改文件名! 请随小生一起批量自动创建、提取、重命名! 1、批量创建文件夹 【案例】创建1日-31日共31个文件夹 【第一步】在A列…

VirtualBox Ubuntu Sever配置双网卡

Ubuntu 版本:Ubuntu Server 2404 vitrualBox 网卡配置: 如上配置后,ifconfig 只能看到 网卡1 应用了。要应用 网卡2 需要更改文件 /etc/netplan/50-cloud-init.yaml(不同的ubuntu版本这个文件名可能不同) 首先 ifcon…

如何在Linux上删除Systemd服务

Systemd是Linux 操作系统的系统和服务管理器,提供控制系统启动时启动哪些服务的标准流程。 有时,您可能出于各种原因需要删除systemd服务,例如不再需要、与其他服务冲突,或者您只是想清理系统。 Systemd使用单元文件来管理服务&…

OBD诊断(ISO15031) 04服务

文章目录 功能简介ISO 9141-2、ISO 14230-4和SAE J1850的诊断服务定义1、清除/重置与排放相关的诊断信息请求消息定义2、请求与排放相关的DTC响应消息定义3、报文示例 ISO 15765-4的诊断服务定义1、请求与排放相关的DTC请求消息定义2、请求与排放相关的DTC响应消息定义3、否定响…

深入详解RocketMQ源码安装与调试

1.源码下载 http://rocketmq.apache.org/dowloading/releases/ 2. 环境要求 64位系统JDK1.8(64位)Maven 3.2.x

keil5模拟 仿真 报错没有读写权限

debug*** error 65: access violation at 0x4002100C : no write permission 修改为: Dialog DLL默认是DCM3.DLL Parameter默认是-pCM3 应改为 Dialog DLL默认是DARMSTM.DLL Parameter默认是-pSTM32F103VE

计算机网络——数据链路层(点对点协议PPP)

点对点协议PPP的概述 对于点对点的链路,目前使用得最广泛的数据链路层协议是点对点协议 PPP (Point-to-Point Protocol)。 它主要应用于两个场景: 用户计算机与ISP之间的链路层协议就是点对点协议 PPP,1999年公布了回以在以太网上运行的PPP协…

配音软件有哪些?分享五款超级好用的配音软件

随着嫦娥六号的壮丽回归,举国上下都沉浸在这份自豪与激动之中。 在这样一个历史性的时刻,我们何不用声音记录下这份情感,让这份记忆以声音的形式流传? 无论是制作视频分享这份喜悦,还是创作音频讲述探月故事&#xff…

AI 会淘汰程序员吗?

前言 前些日子看过一篇文章,说国外一位拥有 19 年编码经验、会 100% 手写代码的程序员被企业解雇了,因为他的竞争对手,一位仅有 4 年经验、却善于使用 Copilot、GPT-4 的后辈,生产力比他更高,成本比他更低&#xff0c…

【分布式系统】监控平台Zabbix对接grafana

以前两篇博客为基础 【分布式系统】监控平台Zabbix介绍与部署(命令截图版)-CSDN博客 【分布式系统】监控平台Zabbix自定义模版配置-CSDN博客 一.安装grafana并启动 添加一台服务器192.168.80.104 初始化操作 systemctl disable --now firewalld set…

<电力行业> - 《第16课:电力领域(二)》

3 制造 3.1 电气制造厂 发电厂发电需要发电机,变电站升压降压需要变压器,输电线路输送电能需要电缆,这些主要电气设备的制造商,就是电力设备厂家。 电气设备制造是电力领域市场最基础也是最开放的领域,电力行业内最…

BugKu-WEB-sodirty

目录 前言 正文 信息收集 代码审计 验证 结尾 前言 七月始,暑假副本也正式开启 正文 信息收集 看着貌似没啥意义 看样子是有备份文件 下载下来 快速审计一下 代码审计 来吧 app.js没啥东西,主要是功能是实现error 我们找一找有没有index.js 找到了 \www\routes\in…