Skip to the content.

PTools 当前架构

1. Architecture Principles

PTools 面向 iOS 17+ / Swift 6+,优先采用 UIKit、Foundation、PhotoKit、AVFoundation 和 Swift Concurrency 的系统能力。Core 是稳定契约边界,扩展模块可以依赖 Core,但 Core 不依赖 业务模块、Debug UI 或宿主应用。

架构治理遵循:

2. Module Layers

Foundation-only Core values / parsers
                ↓
PToolsCore + PToolsUIFoundation + PToolsPermissionCore
                ↓
ptools / PooTools Core (UIKit, Category, Base, Theme)
                ↓
Network / Media / Navigation / Permission / Feature modules
                ↓
Debug / PTInstruments adapters and Example host

PooTools.podspec 的 default_subspec 是 Core。SwiftPM 通过 PToolsCore、 PToolsUIFoundation、PToolsPermissionCore 和 PToolsPermissionUI 提供分层 target, ptools 继续作为兼容 umbrella;CocoaPods 和 Xcode 保留公开 source membership。

3. Dependency Direction

4. Core Boundary

Core 的长期 canonical 入口包括:

能力 唯一入口 兼容入口策略
场景和当前页面 PTSceneContext 旧全局 window 查询转发并逐步弃用
UI 调度 PTMainActorBridge PTGCDManager 保留兼容入口
图片加载 PTLoadImageFunction.loadImage(source:) 控件、字符串和旧来源入口转发
视频缩略图 PTVideoThumbnailService AVAsset、FileManager 旧方法转发
媒体保存 PTMediaSaveService UIImage、PHPhotoLibrary 和管理器入口转发
空状态 PTUnavailableManager.render Base 和 Collection 只做适配
网络请求 Network request context / executor Any、KakaJSON、callback 保留在兼容层
列表身份 稳定存储的 PTDiffableModel.diffId 旧模型协议不再生成随机 ID

5. Permission Boundary

系统权限请求由各自模块拥有系统 delegate 和请求生命周期,公共状态映射和完成语义放在 Permission Core。请求完成必须 exactly once,并回到 MainActor;restricted、denied、limited、 未决定和系统错误不能让 async 调用永久等待。

Photo Library、Camera、Location、Contacts、NFC、Motion、Notification、Health 等系统对象 不跨模块暴露可变共享状态;需要跨边界时使用结果快照或窄范围包装器。5.16.0 起,IAP、NFC、Motion、 HealthKit、MetricKit 和 GPS 管理器提供幂等的 start()、stop()、invalidate() 生命周期;退出页面或 失效时必须释放系统 delegate、observer、query、session 和待处理回调。

6. Network Boundary

Network 的 Codable、Body、普通参数、上传、下载、callback、async 和 stream 入口最终进入统一 请求上下文。新代码使用 PTNetworkRequest、PTNetworkResponse 和 PTNetworkExecutor;请求上下文 负责 headers、cache policy、retry、dedup、cancellation、认证刷新、错误转换和脱敏日志。旧动态 Any 入口不得进入并发核心执行器,旧 callback 入口只负责适配结果。

缓存按 none、cacheOnly、networkOnly、cacheElseNetwork 和 networkElseCache 处理,并保留 ETag、Last-Modified、Cache-Control、304 与损坏缓存恢复信息。重试必须经过幂等性策略;认证刷新由 actor 合并,避免并发 401 产生刷新风暴。

6.1 Socket / Security Boundary

新 WebSocket 入口是 actor 隔离的 PTWebSocketClient,只交换 PTWebSocketMessage、状态和配置值; PTSocketManager 与 SocketRocket 仅作为兼容适配层保留。连接状态、发送队列、心跳、路径变化和前后台 生命周期由客户端统一管理。

新安全入口是 PTSecurity,只暴露 Foundation、CryptoKit 和 Security.framework 可表达的值类型; Keychain accessibility、生物识别项目、AES-GCM、HMAC、摘要、P-256 签名和验签不把 CryptoSwift、 IOSSecuritySuite 或其他第三方类型泄漏到公共契约。旧安全 API 由兼容层继续维护。

7. Navigation / TabBar

PTBaseViewController、PTBaseNavControl 和 PTBaseTabBarViewController 共享 PTSceneContext 与导航栏样式解析。页面样式按当前栈顶控制器和交互式转场进度刷新,不能读取 另一个导航栈的全局样式。TabBar 外观使用值快照,iOS 26+ 的系统玻璃效果只在可用系统版本启用, 旧系统保持动态颜色和材质回退。

5.13.0 起,导航栏项目在转场回调中绑定到具体的 UINavigationController 和目标控制器;TabBar 的过期转场完成回调会被丢弃,并在安全区、旋转、分屏和台前调度变化后显式恢复可见性状态。

8. Collection / List

PTCollectionView 是列表和集合的统一实现;PTListViewController 只承载一个 PTCollectionView,.Normal 提供类表格布局,其他 viewType 提供 Grid、Waterfall、Tag、 Horizontal 和 Custom。Diffable 更新使用稳定 ID,Cell 复用清理旧请求、generation、手势、 播放器和动画。Skeleton、empty、loading、error 和 content 由统一状态入口管理。

5.13.0 起,Diffable 快照提交在组件内部串行化并报告重叠更新,空 Row 身份和非法列数在进入布局 引擎前被拒绝;PTReusableTaskBag 为高频 Cell 提供统一的异步任务取消和内容重置契约。

8.1 Search Container

PooToolsSearch 的 PTSearchViewController<Item> 通过 PTListViewController 间接继承 PTBaseViewController,复用现有 PTCollectionView 和 PTSearchBar,不引入 UISearchController 的 第二套生命周期。PTSearchState 只在 MainActor 上驱动 UI;请求使用 PTSearchTaskCoordinator 管理 取消,并使用 PTSearchSnapshot 丢弃旧关键词的返回值。

Local、Remote、Hybrid 和 Custom 只改变 Provider 调用方式;History、Suggestion、Pagination、Refresh、 Empty 和 Error 仍经过同一状态机。PTSearchPresentationContext 只保存当前页面的导航栏项目,退出搜索时 恢复 title、左右按钮、自定义 titleView 和导航栏样式,不修改 UIKit 全局 appearance。

Search 是 Core 之上的可选容器:需要输入框的宿主只安装 SearchBar,需要完整页面时再安装 Search。

9. Media

ImagePicker 是轻量系统单媒体入口,PhotoPicker 是自定义 PhotoKit 多媒体入口;两者共存但不 重复承担同一职责。图片请求、视频缩略图、原图数据、媒体保存和导出均使用类型化结果与取消路径。 大图、GIF、视频原始数据和导出对象不能无界长期持有。

5.15.0 起,PooToolsMediaCore 提供 PTMediaAsset、PTMediaType、PTMediaMetadata、 PTMediaResource 和 PTMediaSource 值类型。Core 的 PTImageDownsampler 使用 ImageIO 按目标像素 预算解码,PTMediaCache 以资源、变体、尺寸和帧号生成稳定键,并由 actor 串行化 Memory/Disk 读写和容量维护。视频文件缓存使用独立 .part 文件、Range 续传、并发下载去重和原子提交。 MediaViewer Cell 与 VideoEditor 通过幂等媒体失效入口释放任务、播放器、Live Photo 和 observer。

10. Theme / Appearance

Theme、DarkMode、Colors、Font 和 Alert/ActionSheet 使用动态系统颜色、trait collection 和 safe-area。nil 的背景配置表示使用系统默认动态背景,而不是黑色兜底。Reduce Motion、Reduce Transparency、Dynamic Type 和 VoiceOver 是组件契约的一部分。

11. Scene / Lifecycle

所有窗口、当前页面、Alert、Debug window 和媒体 UI 都通过 PTSceneContext 解析所属 Scene。 不得用全局 key window 代替场景上下文。Scene disconnect 时释放窗口、sink、observer、Task、 delegate 和临时资源;不可逆 runtime hook 由 owner registry 记录,不伪造 undo。

12. Concurrency Model

13. Compatibility Layer

5.x 不删除公开符号。旧入口通过薄包装器调用 canonical implementation,并在 MIGRATION_6.md 登记起始版本和 6.0 删除条件。兼容层不得再复制 业务实现、维护第二套缓存或产生随机 Diffable 身份。

14. Debug Boundary

Debug 与 PTInstruments 的结构、采样边界、隐私和多 Scene 规则见 DEBUG_AND_INSTRUMENTS.md。

14.1 P2 Modern System Extensions

5.36.0 的 Configuration、Feedback、Audio、AppIntents、WidgetCore 和 Activities 是围绕 Core 的可选层,不进入 default_subspec = Core。Configuration/WidgetCore 复用 Storage,AppIntents/ WidgetCore 复用 RouteCore/DeepLink;WidgetCore 保持 Foundation-first,不引入 SwiftUI 视图。 AppIntents、WidgetCore 和 Activities 的 Extension Target 契约、App Group、ActivityAttributes 以及宿主业务 UI 见 PTOOLS_P2_MODERN_EXTENSIONS.md。

15. Verification

当前 module graph、source parity、API baseline、并发 allowlist 和回归结果位于 report/。 静态报告不替代 Xcode iOS 构建、真机、真实宿主和 Instruments 验收。

16. 5.19 Package Governance

包入口和直接依赖不在架构文档中重复维护;安装态映射见 PACKAGE_MATRIX.md,直接依赖和 6.0 取舍见 DEPENDENCY_MATRIX.md。发布版本只从根目录 VERSION 读取,SwiftPM 不额外维护产品版本字段。

17. Canonical documentation ownership

并发规则、系统对象例外和后台工作分类统一维护在 CONCURRENCY.md;构建、质量和 发布流程分别维护在 docs/maintainers/QUALITY.md 与 docs/maintainers/RELEASE.md。历史版本的 Core、P1 和 P2 收口记录已经合并到本架构文档、并发文档、依赖文档和质量文档,不再保留重复的版本化事实源。