ReadViewSDK/Doc/CODING_STYLE.md
shen c0aac56083 docs: 同步 Doc 文档与当前代码状态
- 更新模块文件数(EPUBCore 31+2, EPUBTextRendering 13, ReaderView 5, EPUBUI 19)
- 更新 Swift 版本(5.10)、iOS 版本(15.0)、行数等基本信息
- 补充新增文件文档(TextAnchor, RenderRequest, WebViewDebug, AssetRepository,
  TextIndexTable, TextPerformanceSampler, ChapterData, PageInteractionController 等)
- 更新 RDEPUBLocation 模型(新增 rangeAnchor 字段)
- 更新 RDEPUBReaderConfiguration(13 项配置)、Delegate 签名、Persistence(8 方法)
- 修正 RDURLReaderController 归属(ReaderView → EPUBUI)
- 移除过时的 LegacyRDReaderController 引用
- 标记 SS→RD 命名迁移为已完成
2026-05-25 20:31:10 +08:00

296 lines
13 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.

# ReadViewSDK 代码规范
## 适用范围
本文档适用于 `ReadViewSDK` 新增代码与重构代码。
- 规范覆盖 `Sources/``RDReaderDemo/` 中的 Swift 代码。
- 命名、分层与职责边界以 SDK 可维护性和可扩展性为优先。
- 本文档分为两类内容:
- `已观察到的约定`:当前工程常见写法。
- `建议统一的规范`:后续统一执行的规则。
## 新架构目录与职责
### 已观察到的约定
- `Sources/RDReaderView`:阅读核心容器、翻页能力与基础视图。
- `EPUBCore`EPUB 解析、资源定位、导航状态、分页与会话协调。
- `EPUBTextRendering`:文本渲染引擎与分页支持。
- `EPUBUI`:可开箱即用的 Reader UI 层。
- `RDReaderDemo`:示例应用与调试入口。
### 建议统一的规范
- 新增业务能力优先归入 `Sources/RDReaderView` 下的对应模块目录。
- `Core` 层只承载解析、会话、状态机与通用能力,不写页面级交互。
- `UI` 层只承载展示、事件分发和轻量状态同步,不直接处理底层解析逻辑。
- 若模块持续膨胀,优先在当前模块下继续拆分子文件,不跨目录散落实现。
## 命名规范
### 已观察到的约定
- 当前工程历史命名以 `SS`、`RDEPUB` 开头。
- 控制器常用 `...Controller`,视图常用 `...View`,会话对象常用 `...Session`
- 扩展文件采用 `类型名+功能域.swift`,如 `Parser+Archive.swift`
- 事件方法常使用 `Action` 结尾,例如 `pageTapAction()`、`themeChangeAction()`。
- 绑定数据的方法常使用 `bind`、`update`、`refresh`、`configure` 等动词。
### 建议统一的规范
- **所有新增类型必须以 `RD` 开头。**
- EPUB 相关类型统一以 `RDEPUB` 开头。
- 方法名、变量名沿用 Swift 小驼峰,不增加额外前缀。
- 类型名应反映职责,不使用过宽泛的后缀;只有真正承担协调逻辑时才使用 `Manager`、`Handler`。
- 事件处理方法统一使用"对象/意图 + Action"命名,例如 `pageTapAction`、`themeChangeAction`。
- 数据绑定方法优先使用以下语义:
- `bind...`:将模型绑定到视图或模块。
- `update...`:增量刷新已有界面或状态。
- `configure...`:一次性配置样式或依赖。
- `refresh...`:重新拉取或重建数据状态。
- 避免新增拼写不一致的方法名;若发现历史命名拼写错误,新增代码必须使用正确拼写,旧接口修复时应配合调用点一起调整。
命名示例:
- `RDReaderView`
- `RDEPUBParser`
- `RDEPUBPublication`
- `RDEPUBReadingSession`
- `RDEPUBReaderController`
- `RDEPUBReaderTheme`
扩展文件命名示例:
```text
RDEPUBParser.swift
RDEPUBParser+Archive.swift
RDEPUBParser+Package.swift
RDEPUBParser+TOC.swift
RDEPUBParser+Resources.swift
RDEPUBWebView.swift
RDEPUBWebView+Configuration.swift
RDEPUBWebView+Reflowable.swift
```
## 分层与职责边界
### 已观察到的约定
- 阅读入口负责容器装配、翻页模式切换和事件分发。
- EPUB 核心层负责解析、导航、分页、资源读取与定位。
- 渲染层负责 HTML/富文本渲染与分页支持。
- UI 层负责主题、工具栏、目录、设置等交互能力。
### 建议统一的规范
- `RD...Controller`:负责页面级编排与流程调度,不承载复杂渲染细节。
- `RD...View`:负责展示与局部交互,不承载完整业务流程。
- `RDEPUB...Core`:负责解析、会话状态与数据模型,不依赖具体页面。
- 配置、主题、定位、进度模型统一下沉为 `struct`
- 跨层通信优先通过会话层或协议,不做跨层直接写状态。
## UI 与布局规范
### 已观察到的约定
- 视图多采用 `lazy var` 初始化,并在闭包内完成默认配置。
- 自定义 View 通常在 `init(frame:)` 或业务绑定后调用 `initView()` 完成视图树搭建。
- 复杂页面使用分区 extension 组织代理与事件实现。
- 页面或组件内部按职责拆分样式方法,例如 `topBarStyle()`、`contentStyle()`。
- 页面经常通过回调闭包把交互抛给外层,例如 `pageChangeCallback`、`selectionCallback`。
- 模块内存在多处布局方式混用情况。
### 建议统一的规范
- SDK 层新增 UI 使用 Auto Layout 原生约束Demo 层可使用 SnapKit单文件内不混用多套布局体系。
- 视图层初始化顺序保持一致:
- 定义属性与子视图
-`initView()` 中组装视图树
- 在独立方法中拆分样式和状态刷新逻辑
- 当约束会被多次切换时:
- 首次创建使用 `makeConstraints`SnapKit`NSLayoutConstraint`
- 重建结构使用 `remakeConstraints`SnapKit或先移除再添加
- 仅修改常量时使用 `updateConstraints`SnapKit或修改 `constant` 属性
- 布局分支明显时,优先拆成语义化私有方法,不要把所有状态分支堆在一个超长方法里。
- 对外暴露的 UI 刷新入口建议以 `bind``update` 开头,避免把布局细节暴露给调用方。
- 交互事件通过闭包或 delegate 抛出,避免子视图持有上层业务依赖。
## 交互与状态处理规范
### 已观察到的约定
- 事件处理使用 `@objc` + selector。
- 异步回调中广泛使用 `[weak self]`
- 状态判断常通过 `guard` 提前返回。
### 建议统一的规范
- 按钮、通知、系统回调放入独立 extension 分组。
- 异步闭包默认先使用 `[weak self]`,仅在必要时改强引用。
- 多前置条件入口统一先 `guard` 校验,减少嵌套。
- 导航与进度恢复统一通过 `RDEPUBReadingSession` 协调。
## 代码风格细则
### 已观察到的约定
- extension 分区较常见。
- 解析与渲染模型多数采用 `struct`
- 存在少量历史命名不统一与可选值处理不一致情况。
### 建议统一的规范
- 默认遵循”最小可见性”:`private` > `fileprivate` > `internal` > `public`
- 纯数据模型使用 `struct` + `Codable` + `Equatable`
- 服务对象使用 `final class`,避免无意义继承。
- 错误类型统一使用 `enum + LocalizedError`
- 新增代码避免强制解包;若当前上下文无法避免,至少先在上层收敛边界。
- 统一优先使用 `guard` 做前置失败处理,减少深层嵌套。
- extension 的拆分原则以”单一职责”优先:
- 事件处理一组
- 代理 / DataSource 实现一组
- 工具方法一组
- 通知适配一组
- 调试代码继续使用 `#if DEBUG` 包裹,不把调试边框、日志、测试分支直接带入正式逻辑。
## 文件组织规范
### 已观察到的约定
- 目录按阅读容器、EPUB Core、渲染、UI 分层组织。
- 大类通过 `+Extension` 文件拆分职责。
### 建议统一的规范
- 目录保持以下分层,不跨层放置实现:
- `Sources/RDReaderView/EPUBCore`
- `Sources/RDReaderView/EPUBTextRendering`
- `Sources/RDReaderView/EPUBUI`
- 单文件建议不超过 `600` 行;超出后按职责拆分 extension 文件。
- extension 文件命名统一 `RD类型名+功能域.swift`
## 注释规范
- 注释、错误提示、日志统一使用中文。
- 关键流程方法保留”为什么这样做”的注释,不写重复代码字面行为的注释。
- 调试输出统一放在 `#if DEBUG` 下。
- 新代码保留有信息量的注释,避免重复描述显而易见的代码行为。
## 已观察到的项目模式
### 模式 1统一入口 + 扩展拆分
- `RDEPUBParser` 负责 EPUB 解析主入口,不同能力拆到 `+Archive`、`+Package`、`+TOC`、`+Resources` 等扩展文件。
- `RDEPUBReadingSession` 负责阅读会话主入口,状态管理、分页、定位等能力拆到扩展文件。
- 该模式适合继续用于解析器、会话管理、控制器工具方法等横向能力。
### 模式 2页面编排在 Controller局部交互下沉到 View
- `RDEPUBReaderController` 负责阅读页整体编排:翻页容器装配、工具栏切换、阅读位置恢复。
- `RDReaderView` 负责分页容器布局与翻页交互,并通过 DataSource / Delegate 把数据需求交回外层。
- 该模式保持 Controller 管流程、View 管展示的职责分离。
### 模式 3列表与容器逻辑通过扩展拆开
- 复杂容器将 `UICollectionViewDataSource`、`UICollectionViewDelegate`、`UICollectionViewDelegateFlowLayout` 分别拆分到 extension。
- 该模式降低单文件中主逻辑与代理逻辑的耦合,适合继续用于任何包含列表或容器的组件。
### 模式 4渲染路径抽象
- `RDEPUBReadingProfile` 根据 EPUB 特征自动选择渲染路径(`webFixedLayout` / `webInteractive` / `textReflowable`)。
- 新增渲染相关功能时,必须评估对三种路径的覆盖情况。
## 待统一项
- 当前访问控制级别存在混用:同一类里 `public`、默认 `internal`、`private` 并存,建议后续新增代码默认从最小可见范围开始声明。
- 当前存在少量强制解包,建议新增代码优先通过前置校验收敛风险。
- 当前存在拼写不一致问题,建议后续新增代码统一使用标准英文单词,旧接口如需修复应配合调用点一起调整。
- 当前部分注释偏”过程说明”或遗留调试注释,建议新代码保留有信息量的注释。
- 当前个别 View 在数据绑定阶段再次调用 `initView()` 重建界面,这种方式在复杂组件中容易引入重复添加子视图或状态不一致。建议新增组件优先区分”初始化视图结构”和”刷新数据状态”两个阶段。
## 禁忌事项
| 禁忌 | 替代做法 |
|------|----------|
| 新增类型不加 `RD` 前缀 | 所有新增类型统一 `RD` / `RDEPUB` 前缀 |
| UI 层直接拼装解析状态 | 通过 `RDEPUBReadingSession` 获取状态 |
| 控制器直接操作底层解析细节 | 通过 `RDEPUBPublication`、`RDEPUBParser` 暴露接口 |
| 强制解包可选值 | `guard let` / `if let` |
| 用页号单独恢复阅读进度 | 统一使用 `href + progression` |
## 使用建议
- 新增功能前先确定目录归属和职责边界。
- 命名先定前缀再落代码:类型一律 `RD` 开头。
- 若需迁移历史 `SS` 前缀,按模块渐进替换,优先替换新增与重构触达文件。
## 旧 SS 命名迁移到 RD 的执行状态
**迁移已完成**:源码中已无 `SS` 前缀类型定义,全部使用 `RD`/`RDEPUB` 前缀。新增代码必须继续遵守此规则。
### 阶段 0冻结新增 SS 命名(已完成)
- 目标:从当前时点开始,不再引入新的 `SS`/`RDEPUB` 类型名。
- 动作:
- 新增类型统一使用 `RD`/`RDEPUB` 前缀。
- Code Review 增加命名检查项:发现新增 `SS` 命名必须驳回。
- 在 PR 模板中加入”本次是否新增旧前缀命名”勾选项。
- 验收:
- 新提交代码中,新增类型 `SS` 前缀数量为 `0`
### 阶段 1建立迁移映射表第 1 周)
- 目标:明确“旧名 -> 新名”一一映射,避免多人并行改名冲突。
- 动作:
- 统计核心公开类型、内部核心类型、测试类型三类清单。
- 建立命名映射表,例如:
- `RDReaderView` -> `RDReaderView`
- `RDEPUBParser` -> `RDEPUBParser`
- `RDEPUBReadingSession` -> `RDEPUBReadingSession`
- 对外 API 单独标记“需兼容过渡”的类型。
- 验收:
- 映射表覆盖全部高频核心类型,且团队评审通过。
### 阶段 2先迁移内部类型第 2-3 周)
- 目标:优先改内部实现,降低外部兼容压力。
- 动作:
- 按模块分批迁移:`EPUBCore` -> `EPUBTextRendering` -> `EPUBUI`
- 每批次只改一个子模块,避免超大 PR。
- 同步修复调用点、扩展文件名与注释中的旧命名。
- 验收:
- 目标模块内类型命名全部满足 `RD` 规则。
- 编译通过Demo 阅读主流程可用。
### 阶段 3迁移公开 API 并保留兼容层(第 3-4 周)
- 目标:完成对外接口改名,同时给接入方提供平滑升级窗口。
- 动作:
- 对外公开类型切换为 `RD` 命名。
- 旧公开类型保留兼容别名,并标注废弃说明(`deprecated`)。
- 在 Release Note 提供“旧名/新名对照表”和迁移示例。
- 验收:
- 新接入示例仅使用 `RD` 命名。
- 旧接入代码在兼容期内无需立即改动即可编译。
### 阶段 4清理兼容层与收口下一主版本
- 目标:在约定主版本移除旧前缀,完成命名收口。
- 动作:
- 删除 `SS` 兼容别名与过渡代码。
- 清理文档、注释、示例工程中的旧前缀残留。
- 对外发布最终迁移公告与升级说明。
- 验收:
- 工程内无 `SS`/`RDEPUB` 类型定义残留。
- 文档与示例代码全部为 `RD`/`RDEPUB` 命名。
### 迁移过程约束
- 每次迁移 PR 必须包含:
- 命名改动清单
- 影响范围说明
- 回归验证结果编译、Demo 主流程、关键阅读路径)
- 禁止在同一 PR 中同时做“大规模命名迁移 + 业务逻辑重构”。
- 若改名会影响外部接入,必须先补迁移文档再合并代码。