ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Lona 组件性能优化实践指南:从 Lona Studio 图层精简到 Swift 运行时调优

Lona 组件性能优化实践指南:从 Lona Studio 图层精简到 Swift 运行时调优 设计系统前端开发工具UI组件【免费下载链接】LonaA tool for defining design systems and using them to generate cross-platform UI code, Sketch files, and other artifacts.项目地址https://gitcode.com/gh_mirrors/lo/Lona点击查看免费下载本篇指南围绕 Lona 官方性能文档 studio/docs/performance.md 展开系统讲解如何让 Lona 生成的前端组件尤其是 Swift/UIKit、AppKit 平台运行得更快、代码更精简。你将掌握三大层面的优化手段在 Lona Studio 中通过渲染更少与合理切分组件边界来从源头减负在 Swift 生成代码中通过批量设置Parameters、利用函数参数代理机制来减少update()调用以及在处理表格与集合、压缩生成代码体积时应该遵循的具体取舍原则。文中所有结论均对照仓库内编译器源码与生成示例可直接落地到你自己的 Lona 工作区中。一、性能优化的第一站Lona StudioLona 的性能优化有一条清晰的优先级路径任何能在设计阶段Lona Studio完成的优化成本最低、收益最广——它会影响后续生成的所有平台Swift、JavaScript 等的输出。因此动手写任何平台级优化代码之前先回到.component文件本身。1.1 渲染更少Render Less提升性能最有效的手段是少渲染。在设计组件时尽量用最少、最必要的图层数来完成 UI检查多余的包装View如果一个视图仅用于布局且只有一个子视图那么它很可能可以被移除。此时可以把它身上的 padding 直接改写成子视图的 margin从而减少一层真实视图。删除永久隐藏的图层如果一个图层在任何参数组合下都永远不会可见直接删除即可。这类图层虽然不可见但依然会被生成进代码中可能影响生成 UI 的初始化和布局性能。这条原则对应到生成代码的规模上是立竿见影的——每一层View在 Swift 中都对应一个UIView/NSView实例及其约束集合层数越少运行时对象越少。1.2 改善组件边界Component BoundariesLona 生成的组件遵循参数变化才重渲染的模型只有参数发生变化时组件才会重新执行其逻辑并刷新 UI。基于这个模型可以围绕组件边界做两项优化拆分巨型组件如果一个单体组件拥有大量图层修改它任何一个参数都会触发整棵视图树的重渲染成本较高。如果其中有一小块 UI 很少变化就把它抽成独立的子组件由大组件把相关参数传递给它。这样大部分参数变化只会触发小块区域的重渲染。利用列表/集合中的实例化与配置分离当组件被用在列表或集合视图如UICollectionView、UITableView中时组件的实例化与参数配置通常发生在不同时刻。如果你的 UI 中存在一种特别常见的配置状态可以考虑把它做成组件的初始状态这样大部分布局工作会在实例化阶段一次性完成后续滚动复用单元时只需做少量增量配置。二、Swift 平台优化在 Lona 生成的 Swift 代码里最根本的性能杠杆依然是减少UIView的数量——也就是回到 Lona Studio 中减少图层数。假设你已经在设计阶段完成了图层精简Swift 侧还有以下几类可以继续挖掘的优化点。2.1 Parameters批量设置避免重复执行 update()Lona 为每个组件生成一个Parameters结构体组件对外暴露的每个参数都会封装成该结构体的字段同时组件内部维护一个公开的parameters成员变量。任何一次参数变更都会触发update()——它负责运行组件逻辑、依据参数刷新 UI。从编译器源码可以看清这条调用链在 swiftComponent.re 中parameters变量被声明为带didSet的存储属性didSet中比较新旧值一旦不相等就调用update()var parameters: Parameters { didSet { if parameters ! oldValue { update() } } }而update()本身被生成为private方法见 swiftComponent.re内部包含依据参数刷新所有图层属性、可见性、矢量图层重绘等逻辑。由此得出第一条 Swift 侧优化原则逐个设置参数会让update()执行多次应当一次性构造/修改一个完整的Parameters结构体再整体赋值给组件的parameters属性让didSet只触发一次刷新。例如比起下面这种写法component.title Hello component.subtitle World component.imageName avatar更推荐的做法是var params component.parameters params.title Hello params.subtitle World params.imageName avatar component.parameters params注意Parameters声明为Equatable但这一能力对函数类型参数是名不副实的——Swift 本身不支持函数做相等比较。因此 Lona 在处理函数参数的 setter 时走了另一条路详见下文 2.2。官方文档也提到后续可能移除Equatable的一致性改为提供一个专门比较两个Parameters非函数内容的辅助方法。2.2 函数参数代理变更函数参数不会触发 update()Lona 在函数参数与逻辑之间引入了一层间接代理从而保证组件始终调用到最新传入的函数同时又不必重跑组件逻辑。编译器注释给出了这一设计动机见 swiftComponent.re由于 Swift 不支持函数相等比较目前也无法判断可选函数是否为 nil所以对于函数类型参数Lona 生成了一个handle...形式的私有代理方法它直接调用参数中保存的最新函数引用见 swiftComponent.re完全不经过update()。这带来的性能结论是修改一个函数参数永远不会调用update()——因为在绝大多数场景下函数本身不会影响 UI 布局与外观只是动作回调。这避免了仅因为换了一个回调就让整棵视图树重新刷新的浪费。官方文档同时指出未来会提供一个退出该优化的开关让开发者在个别边缘场景下例如函数变化确实需要影响 UI 时选择让参数变化重新触发update()——该能力目前尚未实现需留意版本演进。2.3 表格与集合Tables CollectionsLona 生成的组件在设计上就是为表格和集合视图UICollectionView/UITableView场景准备的如果在你自己的使用中表现不佳通常需要回到 2.1 的参数批量设置与 1.2 的实例化/配置分离上找原因。关于如何让集合单元获得灵敏的 tap/highlight 反馈状态官方在专门指南 collections.md 中有详细说明可以按需查阅。仓库中也提供了配套的集合视图辅助实现例如生成目录下的 LonaCollectionView.swift。2.4 代码体积条件约束的组合爆炸N² 问题一般情况下生成代码的体积不值得过分担心——因为这些组件本就不该被手工修改。但在两种情况下你需要关注代码量你希望把某个文件移出生成目录、手工修改其中一部分生成代码的体积确实膨胀到了难以维护的程度。此时有两类手段手段一拆分大组件。把大组件拆成多个小组件不会减少代码总量但会让代码分布在更可控的单元里更易维护。手段二减少条件约束conditional constraints的数量。这是代码体积问题的核心来源。当组件根据参数隐藏/显示某个视图时Lona 会生成一组仅在该视图可见时才激活的约束并为每个可见性组合生成一套约束激活方案运行时根据当前哪些视图可见来决定启用哪一套。从编译器实现可以印证这一点在 swiftConstraint.re 中生成逻辑为每一种视图隐藏组合生成一个switch分支随后生成的私有函数conditionalConstraints(...)以每个可能隐藏的视图的isHidden布尔值作为参数见 swiftConstraint.re内部针对每个布尔组合返回对应的约束数组。生成的 Swift 代码大致长这样private func conditionalConstraints(titleViewIsHidden: Bool) - [NSLayoutConstraint] { var constraints: [NSLayoutConstraint?] [] switch (titleViewIsHidden) { case (true): constraints [ bottomViewTopAnchorInnerViewBottomAnchorConstraint, ] case (false): constraints [ titleViewTopAnchorInnerViewBottomAnchorConstraint, ] } return constraints.compactMap({ $0 }) }每个可能隐藏的视图都会给这个函数增加一个布尔维度因此生成的代码量与有时隐藏的视图数量 N呈 N² 关系。对应的优化策略不要隐藏一大堆相互独立的视图而是用一个包装视图wrapper view包住它们只对包装视图做显隐切换。这样 N 大幅下降生成代码显著减少但包装视图会带来渲染性能损耗因此要谨慎使用仅在代码体积确实成为问题时采用把大组件拆分成小组件同样能缓解这个问题N 的基数变小。2.5 组件初始化链路与实例化成本为了理解初始状态优化为何有效值得看一眼组件初始化时发生了什么。Lona 生成的init(parameters:)大致流程为见 swiftComponent.re把传入的Parameters赋值给self.parameters调用super.init(frame: .zero)调用setUpViews()构建视图层级调用setUpConstraints()建立约束调用一次update()完成首次刷新。也就是说实例化阶段天然会完成一次完整配置的工作。如果你把最常见的参数配置做成初始状态Parameters的默认值滚动复用时就可以避免在cellForItemAt之类的回调里做大量差异化配置从而让实例化时做重活、复用时做轻活。三、JavaScript 平台规划中官方文档明确指出JavaScript 平台的优化指南状态为Coming soon...尚未发布。也就是说截至当前仓库版本Lona 的官方性能文档只覆盖了 Lona Studio 设计与 Swift 两大块JavaScript含 React DOM、React Native 等目标暂时没有成文的专项优化说明。对于 JavaScript 目标现阶段可以直接套用本文第一部分的通用原则——在 Lona Studio 里精简图层、合理切分组件——这些优化会传导到所有平台的生成结果上。仓库的生成示例如 examples/generated/test/react-dom 与 examples/generated/test/react-native可以帮你观察同一组件在不同平台下的代码形态便于评估图层精简的实际收益。四、优化路线图小结优化层次核心手段收益Lona Studio全平台通用移除仅用于布局且只有单子的包装 View、删除永久隐藏图层减少所有平台的生成视图数量Lona Studio全平台通用拆分巨型组件、把常见配置设为初始状态缩小每次参数变化的重渲染范围、优化列表复用Swift批量赋值Parameters而非逐参数设置避免update()被多次触发Swift利用函数参数代理机制更换回调不触发update()Swift用包装视图收敛有时隐藏的视图、拆分子组件打破条件约束的 N² 代码膨胀JavaScript暂无官方专项指南Coming soon先复用 Studio 侧优化一句话总结先在设计器里少画再在 Swift 侧少更新、少膨胀——前者是所有平台性能的地基后者是 UIKit/AppKit 场景下最值得关注的两条增量优化路径。备注本文描述的性能特性均基于当前仓库版本。update()的触发时机、函数参数代理行为、条件约束生成策略等细节可在 swiftComponent.re 与 swiftConstraint.re 中直接查看源码确认若升级 Lona 版本请以新版生成代码为准。赞分享设计系统前端开发工具UI组件【免费下载链接】LonaA tool for defining design systems and using them to generate cross-platform UI code, Sketch files, and other artifacts.项目地址https://gitcode.com/gh_mirrors/lo/Lona点击查看免费下载相关推荐Lona 实践指南在 UICollectionView 中集成与调优 Lona 生成的交互式组件Lona 实践指南在 UICollectionView 中集成与调优 Lona 生成的交互式组件 本文面向使用 Lona https://link.gitco设计系统前端开发工具UI组件SwiftDate性能调优指南从启动时间到运行时优化SwiftDate性能调优指南从启动时间到运行时优化 你是否遇到过SwiftDate初始化缓慢、日期处理卡顿的问题本文将从启动时间优化到运行时效率提升全面移动开发Rust-esp32-std-demo项目架构解析深入理解esp-idf-sys、esp-idf-hal和esp-idf-svcRust esp32 std demo项目架构解析深入理解esp idf sys、esp idf hal和esp idf svc Rust esp32 std上一篇从入门到精通career-ops核心组件架构与工作原理分析下一篇U-Net数据预处理完全攻略从原始图像到训练数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表