☰
swiftui-performance-audit - code-smells
2026/10/9 7:41:10 网站建设 项目流程

常见代码异味与修复模式

意图

在代码优先审查期间使用本参考,将可见的 SwiftUI 模式映射到可能的运行时成本和安全修复指导。

高优先级异味

body中的昂贵 formatter

varbody:someView{letnumber=NumberFormatter()letmeasure=MeasurementFormatter()Text(measure.string(from:.init(value:meters,unit:.meters)))}

优先在模型或专用辅助函数中缓存 formatter:

finalclassDistanceFormatter{staticletshared=DistanceFormatter()letnumber=NumberFormatter()letmeasure=MeasurementFormatter()}

重量级计算属性

varfiltered:[Item]{items.filter{$0.isEnabled}}

优先在模型/辅助函数中为每个有意义的输入变化派生一次,或仅在视图真正拥有转换生命周期时才存储派生的视图自有状态。

在body中排序或过滤

List{ForEach(items.sorted(by:sortRule)){iteminRow(item)}}

优先在渲染工作开始之前排序:

letsortedItems=items.sorted(by:sortRule)

ForEach内联过滤

ForEach(items.filter{$0.isEnabled}){iteminRow(item)}

优先使用带稳定身份的预过滤集合。

不稳定的身份

ForEach(items,id:\.self){iteminRow(item)}

对非稳定值或会重新排序的集合避免使用id: \.self。使用稳定的领域标识符。

顶级条件视图切换

varcontent:someView{ifisEditing{editingView}else{readOnlyView}}

优先使用一个稳定的基础视图,并将条件局部化到分区或修饰符。这减少根身份变化并使 diff 更廉价。

在主线程上解码图像

Image(uiImage:UIImage(data:data)!)

优先在主线程之外解码和降采样,然后存储处理后的图像。

观察扇出

iOS 17+ 上的宽泛@Observable读取

@ObservablefinalclassModel{varitems:[Item]=[]}varbody:someView{Row(isFavorite:model.items.contains(item))}

如果许多视图读取同一个宽泛集合或根模型,小的变化可能扇出为广泛的失效。优先使用更窄的派生输入、更小的可观察表面,或更靠近叶子视图的逐项状态。

iOS 16 及更早版本上的宽泛ObservableObject读取

finalclassModel:ObservableObject{@Publishedvaritems:[Item]=[]}

同样的警告适用于传统观察。当许多后代只需要一个派生字段时,避免让它们观察大型共享对象。

修复说明

@State不是通用缓存

将@State用于视图自有状态和有意属于视图生命周期的派生值。不要将任意的昂贵计算移入@State,除非你还定义了它何时以及为什么更新。

更好的替代方案:

  • 在模型或存储中预计算
  • 响应特定输入变化更新派生状态
  • 在专用辅助函数中记忆化
  • 在渲染前于后台任务中预处理

equatable()是条件性指导

仅在以下情况使用equatable():

  • 相等性比较比重算子树更便宜,并且
  • 视图输入具有值语义且足够稳定,可以进行有意义的相等性检查

不要将equatable()作为所有重绘的一刀切修复。

分诊顺序

当多个异味同时出现时,按此顺序优先处理:

  1. 广泛的失效和观察扇出
  2. 不稳定的身份和列表抖动
  3. 渲染期间的主线程工作
  4. 图像解码或调整大小成本
  5. 布局和动画复杂度

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询