Products
GG网络技术分享 2026-04-17 06:28 0

啊, AnyView…一个看似无害的小东西,却能在SwiftUI的性能表现中掀起波澜。作为一名长期混迹iOS开发的“老油条”,我不得不说这玩意儿真是让人又爱又恨。爱它方便灵活,恨它潜在的性能陷阱。最近一段时间,社区里关于AnyView的讨论简直是沸腾了各种“血泪经验”层出不穷。为什么开发者们对它如此关注?主要原因是它真的可能毁掉你的App流畅度!
很棒。 简单AnyView是一个类型擦除的容器。这意味着它可以容纳任何类型的视图,而无需事先知道它的具体类型。这在处理异构视图集合时非常有用,比如在一个列表中显示不同类型的视图单元格。想象一下你正在做一个社交App,需要展示文字消息、 图片消息、视频消息... 如果没有AnyView,你可能需要使用大量的条件判断和泛型代码来处理这些不同的视图类型。有了AnyView,一切都变得简单了——你只需要将它们统统包裹起来即可。
| 视图类型 | 特点 | 适用场景 |
|---|---|---|
| Text | 显示文本 | 静态文本显示 |
| Image | 显示图片 | 图片展示 |
| Button | 可点击按钮 | 用户交互 |
| AnyView | 类型擦除容器 | 异构视图集合 |
与君共勉。 但是!这种便利是以牺牲性能为代价的!主要原因是当SwiftUI渲染一个包含AnyView的视图时它无法知道这个视图的具体类型和结构。这意味着每次渲染都需要重新创建整个视图树,而不是仅仅更新发生变化的部分。
不忍直视。 我最近做了一个小实验,用Stream 的 SwiftUI 聊天 SDK进行测试.先说说使用默认的基于泛型的实现,然后修改代码,将所有的视图都用 AnyView 包裹起来.后来啊一出来我差点没晕过去!
如你所见, 有几个动画卡顿,其中 2 个是橙色的,这意味着卡顿持续时间超过了可接受的延迟时间 33 毫秒。所以呢,在这 2 种情况下将会丢失一帧。这 2 个卡顿发生在加载新消息并将其附加到消息列表时。在加载消息时进行任何后续滚动,不会影响性能,太坑了。。
所以呢,请尽量避免这样的代码:
ForEach { someElement in if someCondition { SomeView }}以及像这样的代码:
ForEach { someElement in AnyView)}在浏览数据时修改
| 测试/实现 | FPS | FPS |
|---|---|---|
| 浏览数据 | 59 | 55 |
| 浏览数据 | 58-59 | ~48 |
16.5%
要理解这个问题,我们需要深入了解SwiftUI的工作原理.SwiftUI采用了一种声明式的编程模型,这意味着你只需要描述你想要呈现的内容,而不需要关心具体的渲染细节.SwiftUI会根据你的描述自动优化渲染过程.,一阵见血。
只是,当你在代码中使用Anyview的时候 , 你相当于告诉SwiftUI “我不告诉你这个视图是什么” 。 大体上... 这就使得 SwiftUi无法有效地利用它的差异算法来优化渲染过程.
想想你去一家餐厅点餐吧!如果服务员知道你要点什么 他可以直接告诉厨房准备这道菜;但如果你只是说“随便给我一样”,服务员就需要向厨房询问所有菜品的信息才能做出决定——这肯定会浪费时间!
替代方案:避免 AnyView 的最佳实践
Apple 也多次提到我们应该避免在 ForEach 中使用 Anyview ,称其可能会导致性能问题 。
Demand feedback