wake-ios/specs/refactor_spec.md

5.8 KiB
Raw Blame History

Wake iOS 重构与性能优化规格说明

版本: v0.1 创建时间: 2025-09-08 15:41 +08

背景与目标

  • 现状问题:代码组织结构一般、页面间切换卡顿(特别是在重动画/媒体加载/网络日志时)。
  • 目标:
    • 提升导航一致性与可维护性(仅保留顶层 NavigationStack + Router
    • 降低页面切换卡顿(减少主线程压力、控制刷新频率、优化媒体与动画负载、收敛网络日志)。
    • 推动 Feature-Oriented 结构与 MVVM降低视图体量与重绘范围。

架构调整总览

  • 统一导航:顶层 NavigationStack(path: $router.path)(见 wake/WakeApp.swift),子页面不再嵌套 NavigationView;使用 Router.shared.navigate/pop/popToRoot
  • MVVM优先对 BlindBoxView 引入 BlindBoxViewModel,将轮询、计时器、媒体预处理、会员信息等迁至 VM。
  • 并发与取消:轮询改 AsyncSequence/Task 可取消;倒计时改 Combine/AsyncTimer统一在 onDisappear/路由变化处取消。
  • 媒体与动画GIF 优先替换为 Lottie 或仅在可见态播放;模糊与缩放动画范围与时机控制;媒体元数据后台计算。
  • 网络日志Debug 可控、限流Release 关闭大段打印;使用 os_log/Logger 分类。
  • 工程结构Feature-OrientedCore/Features/*SharedUI/);延续 Theme/Typography/Spacing 设计系统。

导航设计规范

  • 顶层:WakeApp 中唯一 NavigationStack;其它页面不使用 NavigationView
  • 路由:统一通过 Router.shared.navigate(to:)Router.shared.pop()Router.shared.popToRoot()
  • 返回按钮:子页面通过 Router.shared.pop() 而非 presentationMode.dismiss()

BlindBox 模块重构要点

  • BlindBoxViewModel@MainActor
    • 状态:盲盒列表/单盒数据、会员信息、计时与轮询状态、媒体 URL/尺寸/播放器句柄。
    • 行为:loadBlindBox()start/stopPolling()startCountdown()prepareVideo/Image()、资源清理。
  • 视图拆分:
    • BlindBoxHeaderBlindBoxAnimationAreaLoading/Ready/Opening/NoneBlindBoxActionButtonBlindBoxScalingOverlay
    • 视图仅订阅少量 @Published,降低 body 重绘。

并发与轮询规范

  • 轮询:使用 Task { for await ... in pollSequence } + task.cancel(),严禁无 cancel 的 while + Task.sleep
  • 倒计时:优先 0.25s0.5s 频率;必要时“毫秒展示”不落地 state严格在主线程更新 UI 状态。

媒体与动画规范

  • GIF -> Lottie 优先;若保留 GIF仅在可见态播放避免与大范围模糊+缩放并发。
  • 媒体预热与尺寸探测走后台,回主线程赋值。
  • 播放器生命周期集中管理,页面切换前暂停并释放。

网络日志策略

  • Debug按需与限长打印错误优先可通过开关关闭详细日志。
  • Release关闭大段请求/响应体打印。

工程结构规划(建议)

  • Core/Utils/Network/Auth/Router/Theme/Typography/
  • Features/BlindBox/View/ViewModel/Models/API/Components/
  • Features/Subscribe/:含 CreditsInfoCardPlanCompare
  • Features/Memories/
  • SharedUI/Buttons、LottieView、SVGImage、SheetModal 等

实施计划(分阶段)

  • 第一阶段12 天,先解卡顿):
    1. 统一导航:移除子页面 NavigationView,使用顶层 NavigationStack + Router
    2. 计时器降频0.250.5s;如非必要移除毫秒级显示。
    3. GIF 限制播放或替换为 Lottie关/收敛网络大日志。
  • 第二阶段24 天): 4) 为 BlindBox 引入 ViewModel迁移副作用与状态。 5) 轮询改为可取消的异步序列;媒体预热与尺寸探测后台化。 6) 视图拆分与体量控制。
  • 第三阶段(持续): 7) 目录重组ViewModel 标注 @MainActor;保留 os_signpost 监测关键路径。

验收标准DoD

  • 导航:仅顶层 NavigationStack;子页面无 NavigationView
  • 性能:转场掉帧率明显下降;主界面进入/退出动画流畅。
  • 结构:BlindBoxView < 300 行,主要状态/副作用位于 ViewModel。
  • 资源GIF 仅在可见时播放或替换为 Lottie网络日志按需输出。

任务清单(同步 todo

  • nav-1 统一导航(移除子页面 NavigationViewRouter 返回)
  • mvvm-1 BlindBox 引入 ViewModel迁移逻辑
  • timer-1 计时器降频与取消
  • polling-1 轮询可取消化
  • media-1 媒体与动画优化GIF->Lottie/可见播放)
  • concurrency-1 @MainActor 与线程安全
  • netlog-1 网络日志开关与限流
  • structure-1 目录重组
  • perf-1 性能埋点与基线

进度记录(每次执行后更新)

  • 2025-09-08 15:41 +08: 创建 specs 目录与本说明v0.1)。
  • 2025-09-08 15:41 +08: 完成 nav-1第一步移除 wake/View/Blind/BlindOutCome.swiftwake/View/Memories/MemoriesView.swift 中的 NavigationView,改为使用 Router.shared.pop() 返回;依赖顶层 NavigationStack
  • 2025-09-08 15:51 +08: 继续完成 nav-1
    • 移除 wake/View/Credits/CreditsDetailView.swiftwake/View/Welcome/SplashView.swiftwake/View/Owner/SettingsView.swiftwake/View/Components/Upload/MediaUpload.swift(示例 MediaUploadExample)、wake/View/Examples/MediaDemo.swift 中的 NavigationView
    • wake/View/Feedback.swiftFeedbackViewFeedbackDetailView 的返回行为从 dismiss() 统一为 Router.shared.pop()
    • 保留预览Preview中的 NavigationView,运行时代码已全部依赖顶层 NavigationStack + Router

决策记录

  • 采用顶层 NavigationStack + Router,子页面取消 NavigationView
  • BlindBox 优先落地 MVVM 重构,其它模块随后跟进。