mcpField
U
uikit-app-modernization

uikit-app-modernization

github.com/superagents-lab开发353696 次安装20 周前更新
代码仓库

关于 uikit-app-modernization

面向 Swift 和 Objective-C 项目的 UIKit 现代化技能,针对旧共享状态 API、应用生命周期和固定界面尺寸假设提供定向迁移指导。强调保留控制流、按调用上下文选择替代 API,并处理多窗口与可调整尺寸界面。

主要功能

  1. 01替换旧共享状态 API
  2. 02迁移到场景生命周期
  3. 03支持可调整尺寸和多窗口
  4. 04更新屏幕与方向相关用法
  5. 05遵循定向修改和验证规则

适用场景

  1. 01将 UIKit 应用迁移到场景生命周期
  2. 02移除对主屏幕尺寸的依赖
  3. 03修正安全区域和界面方向假设

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/superagents-lab/xcode27-skills --skill uikit-app-modernization

安装后在 Claude Code 中输入/uikit-app-modernization确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
orientation-task.md
safe-area-task.md
scene-lifecycle-task.md
uiscreen-task.md

详细介绍

UIKit 应用现代化技能

目的

使 UIKit 应用在现代 iOS 上正常运行,方法包括:

  • 消除对旧版共享状态 API 的引用
  • 从应用生命周期迁移到场景生命周期
  • 支持动态场景尺寸和多窗口环境

范围

此技能会对 Swift 和 Objective-C 代码库进行特定且有针对性的现代化改造:

  • 使用适合上下文的现代 API 替换旧版共享状态 API
  • 迁移到基于场景的生命周期
  • 移除以下内容的使用,以更新应用,使其支持可调整大小的用户界面:
    • 主屏幕(UIScreen.mainScreen、UIScreen.main)
    • 界面方向(interfaceOrientation)
    • 对安全区域对称的假设(safeAreaLayoutGuide、safeAreaInsets)

核心原则

  1. 最接近使用方——优先选择最接近使用点的信息(例如,优先使用视图的特征集合,而不是窗口的)。
  2. 只要目标 API 存在,就始终应用替换。 只留下 TODO 属于失败。包含目标 API 的文件若没有任何差异,也属于失败。 如果文件包含目标弃用 API,且依据当前任务参考文件中的任一模式可以进行具体替换,就应用替换。只有当目标 API 仅出现在死代码(#if 0/#endif)中时,才跳过。如果两个有效替换方案难以取舍,选择最符合用户请求的方案,不要因此产生空差异。绝不要默默跳过文件:如果你不愿意应用更改,就与用户讨论可能的选项——绝不要对此不作任何输出。不要在简单文件的边缘情况上陷入纠结;替换显而易见时,就应用并继续。
  3. TODO 必须可执行。 你留下的每个 TODO 都必须说明:(a)为什么需要更改;(b)正确的替换方案是什么;(c)任何生命周期或线程方面的注意事项。将 TODO 单独放在未更改代码上方一行,绝不要内联。含糊的 TODO(“以后再修”)比没有 TODO 更糟;它只会占用审核注意力,却没有提供下一位读者无法自行推断的信息。
  4. 已有注释说明迁移时,不要添加多余的 TODO。 如果调用点已经有与错误报告引用配对的 #pragma clang diagnostic ignored、已有的 // TODO,或指明迁移方式的弃用注释,就不要再添加一个。只有当新 TODO 能提供现有注释中没有的迁移指引时,才添加。
  5. 进行有风险的代码更改前,先询问用户;只有无法互动时才退而使用 TODO。 如果替换有可能破坏调用方或改变可观察行为(例如更改其他模块导入的头文件中的方法签名,或在左右方向有意义时用 width > height 替代方向判断),第一步应询问用户如何处理。只有在技能以非交互方式运行,或用户明确拒绝提供指引时,才添加 TODO 并继续。这不适用于当前任务参考文件指定的标准、安全、可直接替换方案——依据核心原则 2,必须应用这些方案。
  6. 遵循用户的明确指示;否则采用任务参考文件中的默认设置。 如果用户要求特定做法——某个属性、参数名称、参数位置、特征来源或回退行为——就严格照做。不要擅自替换成你认为更现代的方案。如果用户的要求比较笼统(“将这个应用现代化”“修复 UIScreen.main 的用法”),就采用当前任务参考文件中的默认设置。
  7. 绝不要用字面量替换动态值——始终让替换值保持动态。
  8. 保留控制流——优先使用能维持原代码结构的直接替换。只有直接替换行不通时,才添加 guard 或提前返回模式。修改控制流(if/else、switch/case/default、do/catch)附近的代码时,确认编辑后分支结构仍然完整。除非用户明确要求,否则绝不要移除分支(} else {、default:、catch)。将 if/else 合并为顺序执行的差异属于严重错误——这样会导致两个分支无条件执行。
  9. 严格限定范围——不要顺手清理。 只修改包含当前任务目标弃用 API 的行。不要顺便修复附近的其他弃用问题。不要删除行尾空格、重新排版空行,也不要“清理”周边格式。即使发现相邻行有明显的现代化改进,也不要改动——每项任务相互独立,范围外的更改会让原本成功的范围内修改变成警告。
  10. 提取重复表达式——当同一替换值在一个作用域中多次使用时,将其提取为具名局部变量。
  11. 绝不要遍历全局场景或窗口状态——绝不要使用 UIApplication.shared、UIDevice.current、UIScreen.main 或其他共享对象作为替代。如果没有可用的本地对象,就修改方法以接受新参数,并将旧方法弃用。
  12. 模式必须完整——原子应用,绝不部分应用——每种多部分模式都必须一次性完整应用所有部分。弃用并转发需要同时包含弃用、新重载和转发——如果模式要求提取方法,就绝不能只做内联替换。当当前任务要求同时进行 API 替换和响应式更新(例如,特征变化观察)时,两者构成一个完整的原子更改——绝不能只应用其中一项。 将弃用并转发模式降级为对共享对象的内联引用属于错误——这会移除调用方赖以找到新 API 的已弃用桥接,从而悄然破坏迁移过程。如果无法完成全部四个部分(使用正确参数名称、类型和位置的新重载;旧方法通过共享状态(例如 UITraitCollection.current、UIScreen.main)委托调用;旧方法标记为弃用并使用适当的属性;保留已弃用的包装方法),就不要应用部分更改——要么完成完整模式,要么说明明确理由并跳过。
  13. 添加新重载时,绝不要移除旧方法。 应用弃用并转发模式时,旧方法必须保留在文件中,作为通过 .current 转发到新重载的已弃用包装方法。删除旧方法(即使它在差异中看起来未被使用)也会移除代码库中的弃用信号,并悄然删除迁移桥接。这适用于 Objective-C 方法、Swift 方法、Swift 初始化器、计算属性和协议扩展方法。如果你发现自己在添加新重载时要删除某个方法,请停下——应该保留它并添加弃用属性,而不是删除它。
  14. 保留无关的防护和回退逻辑。 移除 UIScreen.mainScreen 引用时,只更改该引用。不要同时删除 respondsToSelector: 检查、屏幕为空的保护、if (screen != nil) 防御、版本检查(#available、@available)或调用点周围的其他防御逻辑——除非用户明确要求。每项防护都有独立用途(跨 SDK 版本的选择器可用性、窗口为空时的安全性、功能标志);现代化只涉及从屏幕获取的值,不涉及周围的控制流。
  15. 在触及弃用 API 的最低层方法上应用弃用。 如果多个调用方都流向一个实际读取了已弃用共享状态的辅助方法,就在辅助方法上应用弃用并转发,而不是在每个公开调用方上应用。若只有辅助方法需要 traitCollection: 参数,却要求每个公开调用方都增加该参数,就会造成过大的改动范围,并扩大迁移的影响面。相反,如果每个公开调用方内部都直接读取了已弃用状态(没有辅助方法),弃用就应加在这些公开调用方上——没有更低层的方法可供弃用。**经验法则:**找出包含原本需要更改的那一行的方法;弃用该方法。弃用链的扩展范围只应覆盖实际触及已弃用 API 的部分。
  16. 避免替换非目标内容。 编辑任何一行之前,请先确认两点:(a)该行包含当前任务的目标弃用 API;(b)你修改的是用户要求处理的弃用内容,而不是附近看起来“类似”的一行。

工作流

阶段 0:简单情况的快速处理

在查看决策树之前,先检查该用法是否符合简单情况。 很多 UIScreen.main/UIScreen.mainScreen 用法,都是在 UIView/UIViewController 实例方法中直接替换并即时使用值。这些情况无需分析——只需替换后继续:

原始写法替换为
在 UIView/UIViewController 实例方法中内联使用(未存储)的 UIScreen.main.scale(Swift)self.traitCollection.displayScale
在 UIView/UIViewController 实例方法中内联使用(未存储)的 [UIScreen mainScreen].scale(ObjC)self.traitCollection.displayScale
在 layoutSubviews、drawRect:、updateConstraints 或 viewIsAppearing: 中使用的 UIScreen.main.scaleself.traitCollection.displayScale(无需注册——UIKit 会在特征变化时自动调用这些方法)

不要过度思考简单替换。 如果所属类是 UIView/UIViewController,且该值没有赋给 ivar、图层属性、约束或已存储的图像,只需替换即可。简单文件中没有差异是最常见的错误——应用替换后继续。 只有在不符合简单情况时(非视图类、缓存值、类/静态方法、特殊用户指示),才查看决策树。

阶段 1:检测

使用每个相关任务文件中的检测模式,找出需要现代化的用法。对任务注册表中适用于此代码库的每项任务都运行检测,而不只是运行一项——请参阅下方的任务注册表。

阶段 2:分析

对于每处用法,阅读周边上下文以了解:

  • 类层次结构(UIView/UIViewController 子类,还是普通 NSObject 或非视图类)
  • 方法类型(实例方法、静态方法、自由函数、缓存的 dispatch_once 辅助方法)
  • 生命周期阶段(init、viewDidLoad、viewWillAppear、layoutSubviews)
  • 代码意图(布局、渲染、显示缩放比例、全屏尺寸)

当前任务的参考文件可能会为此列表添加特定任务的要点。

使用子代理识别需要更新的代码,以缩小上下文窗口。

阶段 3:决策与验证
条件操作
存在安全的一对一替换方案直接应用。 不添加任何注释(不加 // TODO: FIXME、// TODO 或 // FIXME——只做替换)。使用当前任务参考文件中指定的替换方案。
存在多种有效方案,或代码迁移超过 10 行询问用户。
无法安全替换(极少见)添加待办事项,明确列出交由用户处理的任务。绝不能静默地产生空差异。在得出不适用的结论之前,使用子代理重新检查每种模式。

在修改任何代码之前,使用子代理依据当前任务的 Post-file Checklist 进行验证。

阶段 3b:文件处理完整性

处理每个包含目标弃用 API 的文件。 不要提前停止、跳过文件,也不要悄悄将文件从待处理队列中移除。阶段 1 中识别出的文件,如果没有产生差异,也没有说明跳过原因,就属于处理失败。

明确跟踪文件: 开始处理时,使用可用的任务 / 待办工具或 Markdown 文件,列出所有需要修改的文件。处理每个文件时,将其标记为已完成。完成前,将这份列表与输出进行核对——任何没有差异或明确跳过原因的文件,都必须在完成前处理。

上下文长度: 如果担心上下文长度,请使用子 Agent 处理单个文件或任务。

防止静默遗漏: 完成前,使用子 Agent 对比收到的文件列表与实际生成输出的文件列表。如果有文件未出现在输出中,请返回并处理。静默遗漏的常见原因:

  • 文件大小: 大型文件(1000 行以上)也必须处理。不要例外。
  • 复杂性: 包含预处理器宏、复杂类层次结构或特殊代码模式的文件仍需修改。
  • 项目分组: 不要跳过某个特定项目或目录中的所有文件。如果发现同一项目中的多个文件被遗漏,说明可能存在系统性问题——请调查并修复。
  • 存在歧义: 如果不确定如何修复文件,请询问用户——不要悄悄生成空差异。

大型或复杂文件: 大量使用预处理器(#if / #ifdef 嵌套)、超过 1000 行,或包含较少见模式(C++ 互操作、dispatch_once 缓存、深层嵌套宏)的文件也必须处理。如果此类文件中出现目标 API,请按相同的决策树处理。如果文件太大,无法一次编辑完成,请逐个处理弃用 API 的用法。必要时可使用子 Agent。如果确实无法根据宏展开或预处理器的复杂性判断出安全的替代方案,请询问用户——绝不要悄悄跳过。

批量处理规范: 处理文件列表时,不要先分析所有文件,再一次性生成所有差异。应当逐个文件或按小批次(3–5 个文件)处理:阅读上下文、作出决定、生成差异,然后再处理下一批。这样可避免因输出限制或上下文耗尽而遗漏列表末尾的文件。如果发现生成输出的文件少于收到的文件,请立即停止,处理剩余文件后再完成。

如果发现某些文件的差异为空,而它们本应可以直接替换,请返回并处理这些文件——简单文件处理起来很快,绝不应被遗漏。

阶段 4:实施

应用当前任务参考文件中的实施门槛、规则和文件处理后检查清单。针对特定模式的决策树、门槛问题和验证规则,位于各任务文件中与其对应的模式旁。使用子 Agent 进行验证。

阶段 5:最终验证

文件覆盖审计: 使用子 Agent 对比收到的文件列表(或阶段 1 中检测到的文件列表)与实际生成差异的文件列表。每个输入文件都必须有非空差异。如果有文件缺少更改,请返回并立即处理。

当前任务的参考文件可能会补充特定任务的验证步骤。

任务注册表

除非开发者的请求明确限定了范围,否则请将此注册表中的每项任务都应用于代码库。每项任务相互独立,并在其参考文件中包含自己的检测模式、决策树和验证规则。请按从上到下的顺序执行。

任务文件描述
UIScreen.main 现代化uiscreen-task.md将 UIScreen.main 替换为符合上下文的 API
userInterfaceOrientation 现代化orientation-task.md使用尺寸类别或窗口边界替换与布局相关的方向检查
场景生命周期迁移scene-lifecycle-task.md将 AppDelegate 迁移到 SceneDelegate
安全区域内边距safe-area-task.md使用安全区域引用替换硬编码的内边距值,并确保现有引用适用于不对称安全区域

评论

支持 Markdown