Files
suixinkan_uikit/AGENTS.md
汉秋 05804ba7d6 完善钱包提现状态展示与举报摄影师列表交互。
对齐 Android 提现进度与时间线映射,优化钱包与积分兑换页刷新逻辑,并补充相关单元测试与真机测试说明。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 16:51:32 +08:00

88 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 必注释、保持简洁