对齐 Android 提现进度与时间线映射,优化钱包与积分兑换页刷新逻辑,并补充相关单元测试与真机测试说明。 Co-authored-by: Cursor <cursoragent@cursor.com>
4.9 KiB
suixinkan
项目概览
Swift + UIKit 工程,MVVM 架构。iOS 版 随心瞰商家版,与 Android ZhiFlyFollow 功能对齐——以 Android 工程为参考同步实现业务能力,UI 按 UIKit 习惯编写,不逐行翻译 Compose。
Android 参考: /Users/hanqiu/Desktop/android_project/zhiflyfollow(com.zhifly.follow)
文档: CLAUDE.md、docs/home/、docs/排队叫号业务流程梳理.md
后端: 生产 api.zhifly.cn,测试 api-test.zhifly.cn
主要功能域: 首页/订单/数据/我的 Tab;登录注册与实名认证;订单/任务/核销;相册与云存储;直播与钱包;景区排队叫号、位置上报;消息、设置、扫码、语音通话等。
同步约定: 接口与业务流程以 Android NetworkApi / DTO / ViewModel 为准;UI 用 SnapKit 独立设计;OTG 相机、DJI 飞控、厂商推送等 Android 专属能力按需评估。
平台与设备
iOS 16+ · 仅 iPhone · 仅竖屏。不做 iPad / 横屏 / 低版本 API 适配。
架构(MVVM)
| 层级 | 职责 |
|---|---|
| View | UIViewController / 自定义 UIView,UI 展示与交互,不含业务逻辑 |
| ViewModel | 业务逻辑与状态;通过方法、delegate 或明确回调与 View 通信 |
| Model | 数据模型、网络/本地数据源 |
- 新增功能:对应 Model + ViewModel + ViewController,同步单元测试
- ViewModel 不依赖 UIKit 视图类型
开发风格
命令式 UIKit,不用 @Observable / ObservableObject / @Published、不用 Combine 驱动 UI、不堆泛化 onChanged 回调。
- 在明确时机(点击、网络回调、页面出现)主动刷新 UI(
apply(snapshot)或更新子视图) - 通信用 delegate、target-action 或语义明确的单一回调
- 对照 Android 行为 用 UIKit 重写,不翻译 Compose 语法
- ViewModel 属性供读取,UI 更新由 View 在回调中主动触发
Swift 并发与 Actor
工程 Default Actor Isolation 配置为 nonisolated(suixinkan 与 suixinkanTests 均为 SWIFT_DEFAULT_ACTOR_ISOLATION = nonisolated)。新类型默认不隐式绑定 @MainActor,与命令式 UIKit + 显式刷新风格一致。
| Target | Default Actor Isolation |
|---|---|
suixinkan |
nonisolated |
suixinkanTests |
nonisolated |
编写约定:
- ViewModel / Model:保持
nonisolated,不依赖默认 MainActor;纯逻辑与校验可用nonisolated static。 - 需要主线程的类型:在类型上显式标注
@MainActor(如APIClient、AuthAPI、ProfileAPI、NetworkServices、OSSUploadService、AppRouter)。 - UI 更新:在
UIViewController内通过Task { @MainActor in ... }或已在主线程的回调中刷新 UI,不假设 ViewModel 调用方一定在主 Actor;onStateChange回调应切回主线程再改 UI。 - 网络与可发送类型:请求/环境等跨边界类型保持
nonisolated+Sendable(如APIRequest),避免无意引入 actor 隔离冲突。 - 单元测试:target 默认为
nonisolated;MockURLSession等替身保持nonisolated。需要构造@MainActor类型(APIClient、AuthAPI等)的测试类应显式标@MainActor。
新增代码不要为「凑隔离」给 ViewModel 或普通 model 加 @MainActor;仅 UI 入口、共享网络单例等确需主线程协调处显式标注。
代码注释
class / struct / enum、协议及公开 API 必须写 /// 文档注释,说明职责与用途;复杂内部逻辑按需补充。不写废话注释、不写过时注释。
技术栈与库
Swift · UIKit · SnapKit(代码布局,约束写在 setupUI() / setupConstraints())· Kingfisher(kf.setImage(with:) 加载网络图,列表利用缓存)
列表展示
- 简单列表 →
UITableView;复杂列表(网格、卡片、不等高)→UICollectionView+ Compositional Layout - 数据更新用 Diffable Data Source +
apply(_:animatingDifferences: true),Item 遵循Hashable,避免reloadData() - ViewModel 提供数据,View 构建 snapshot 并 apply
单元测试
每增一功能必须附带单元测试且全部通过,与功能同次提交。单元测试必须在已连接的 iPhone 真机上运行,不使用模拟器;支持使用与开发机处于同一 Wi-Fi 下并已启用无线连接的真机。可在 Xcode 中选择真机后执行 Cmd + U,或使用 xcodebuild test -destination 'platform=iOS,id=<设备 UDID>'。
| 层级 | 优先级 |
|---|---|
| ViewModel / Model | ✅ 优先 |
| View | 按需 |
测试放 suixinkanTests/,独立可重复,mock 网络与外部依赖。
开发注意
- SnapKit 布局、Kingfisher 图片、Diffable 列表带动画
- 以 Android 工程为功能参考,命令式 UIKit,不用 Observable / Combine
- 新增功能必测、类型与公开 API 必注释、保持简洁