Skip to main content

swift

专为 iOS/macOS 现代开发打造的代码分析规范。全面剖析 SwiftUI 响应式模式、ARC 强引用循环破除、以及 Swift 5.5+ 下基于 Actor 与 async/await 的全新并发架构。

Source facts

Repository
microwind/ai-skills
Last source activity
March 29, 2026 at 02:54
Detected SKILL.md language
Chinese
Stars
88
Forks
24

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
Swift 分析大师与苹果生态架构指南
description
专为 iOS/macOS 现代开发打造的代码分析规范。全面剖析 SwiftUI 响应式模式、ARC 强引用循环破除、以及 Swift 5.5+ 下基于 Actor 与 async/await 的全新并发架构。
license
MIT
# Swift 静态分析与现代化架构生态 (Swift 5.9+) ## 概述 Swift 自从取代 Objective-C 以来,经过多年迭代已经成为了一门兼具安全、极速与表现力的现代语言。由于深度绑定 Apple 生态圈,它的开发范式经历了从 UIKit Delegate 时代到现代 **SwiftUI** 与 **Combine** 声明式的巨大转变。 同时,自 Swift 5.5 引入的 **Structured Concurrency (结构化并发, async/await)** 和 **Actors** 打破了长期统治苹果开发生态的 GCD (Grand Central Dispatch / DispatchQueue) 回调地狱。然而,伴随着 `closures` (闭包) 和 `class` 的大量混用,ARC 面临的最大隐性克星 —— **强引用循环 (Retain Cycles)** 导致内存泄漏 (Memory Leak) 在项目中依然屡见不鲜。 **核心原则**: "防微杜渐,声明优先"。对所有的引用传递敲打问号;在跨越系统边界处主动斩断强依赖树;摒弃手动维护状态,使 UI 只做驱动模型状态的反射。 ## 何时使用 **始终:** - 开发苹果全家桶原生应用 (iOS / macOS / visionOS / watchOS)。 - 维护或升级使用了老旧 `@escaping` 闭包和 `NotificationCenter` 的陈旧代码库。 - 将复杂交互迁移至 `SwiftUI` 响应式视图体系。 - 解决 Xcode Memory Graph 发出的交叉持有的警告并排查由于 Navigation 引发的爆内存退场。 **触发短语:** - "如何解决 Swift 闭包里的 Retain Cycle 并优化 weak self 用法?" - "推荐一些从 GCD 迁移到 Swift async/await 的最佳实践。" - "SwiftUI 里面 @State, @Binding 和 @Observable 怎么区分,不要乱用?" - "Actor 怎么避免 Swift 里的数据竞态 (Data Race)?" - "如何优化 Swift 的编译速度和庞大项目结构?" - "请给我一个 iOS Clean Architecture 或 MVVM 的防腐结构向导。" ## Swift 专项分析机制 ### 自动引用计数与生命周期探测 (ARC & Memory Leaks) - **闭包循环检测 (Closure Retain Cycle)**: 拦截在闭包中直接通过 `self.method()` 导致的隐式强捕获,强制提醒并重构为 `[weak self]` 或 `[unowned self]`。 - **委托协议生命周期 (Delegate Patterns)**: 防治未被 `@propertyWrapper` 或 `weak` 修饰的 Delegate 指针,导致子控制器锁死父控制器的释放链。 - **大值隐患 (Value Type bloat)**: Swift 中的 `struct` 是按值传递(Copy-on-Write)。检测在集合或大型状态容器中引发隐式全量深拷贝的低效操作。 ### 现代化并发架构 (Structured Concurrency) - **GCD 滥用 (DispatchQueue Hell)**: 找出深层嵌套的 `DispatchQueue.main.async` 并指导迁移向更为线笥的 `await MainActor.run`。 - **并发状态不一致 (Data Races)**: 验证在跨线程边界传递的类型是否符合 `Sendable` 协议要求,以及非线程安全的 Class 是否需要重构为 `actor` 以保证内部状态互斥。 ### SwiftUI 响应式与数据流设计 - **冗余数据绑定 (Excessive Binding)**: 静态侦探传递了过多并不需要的 `@State` 到子视图导致整个 View 树雪崩式重建重绘的问题。 - **StateObject 丢失陷阱**: 诊断将 `@ObservedObject` 误当做状态根拥有者(它会在 View 的重建时被无情摧毁丢失状态),必须替换为 `@StateObject` (iOS 14) 或 `@State` (iOS 17 Observation 框架)。 ## 常见 Swift 反模式与漏洞修复 ### 1. 闭包中的强引用环 (Retain Cycle in Closures) ```swift 问题: 在网络请求或延时任务的闭包中,隐式或显式地持有了 self。导致当前对象与闭包相互持有内存永远无法被 ARC 释放。 错误示例: class ProfileViewModel { var name: String = "Unknown" let networkService = NetworkService() fun fetch() { // 危险:escaping 闭包强持有了 self networkService.request { result in self.name = result.name // 这里隐藏着 self 强引用! } } } 解决方案: 必须打断这条强环,声明捕获列表并在访问前安全绑定。 fun fetch() { networkService.request { [weak self] result in // 使用 guard let 模式在闭包顶部安全解包 guard let self = self else { return } self.name = result.name } } ``` ### 2. 混合回调与结构化并发 (Callback Hell vs async/await) ```swift 问题: 过时的 API 设计使用连续的回调,这不仅丢失了异常传播机制 (Error Propagation),也容易在多个分支中遗漏调用 completion 导致程序死锁。 错误示例: func fetchUserAndSave(id: Int, completion: @escaping (Result<Bool, Error>) -> Void) { db.fetchUser(by: id) { result in switch result { case .success(let user): api.sync(user) { result2 in // 陷入无尽的回调层级 completion(.success(true)) } case .failure(let error): completion(.failure(error)) // 极其容易因为遗漏这行导致外部挂死 } } } 解决方案 (重构为 Swift 5.5 的 async/await): func fetchUserAndSave(id: Int) async throws -> Bool { // 线性的、抛弃深渊回调的极其优雅的代码,异常会像正常的同步代码一样冒泡! let user = try await db.fetchUserAsync(by: id) try await api.syncAsync(user) return true } ``` ### 3. SwiftUI 状态树崩溃与重绘灾难 (SwiftUI Re-render Bloat) ```swift 问题: SwiftUI 的 View 是非常轻量的描述体。当状态改变时它会被瞬间重构。如果混淆了状态的依赖与所有权,应用就会卡顿。 错误示例: struct ProfileView: View { // 毒药:这里用 @ObservedObject 接收了一个自建对象 // 当父级任何状态改变引发 ProfileView 被重新评价时,ViewModel 会被销毁并重新初始化并再次触发网络请求! @ObservedObject var viewModel = ProfileViewModel() var body: some View { ... } } 解决方案: 如果是视图自己拥有的状态模型,必须告诉 SwiftUI 在自身生命周期中存续它。 struct ProfileView: View { // 正确的做法:@StateObject (如果部署目标 < iOS 17) // 如果部署 iOS 17 以上则直接配合 @Observable 宏使用 @State var viewModel = ProfileViewModel() @StateObject var viewModel = ProfileViewModel() } ``` ## 代码实现示例:Swift 静态风控扫描器 以下为构建的一套原型扫描器分析器引擎,由于 Swift 特有的 `weak self` 及复杂的特有标记(`@State`, `@MainActor`),在实际业务中能产生巨大的排雷作用。 ### Python版 Swift 架构探查器 (Swift-Analyzer) ```python import os import re import json class SwiftAnalyzer: """ 专为 Swift 5.5+ 及 SwiftUI 时代打造的辅助静态分析工具。 探测常见的弱引用遗漏、错误的并发调度策略以及过期的逃逸闭包应用。 """ def __init__(self): self.issues = [] self.metrics = { 'lines_of_code': 0, 'classes': 0, 'structs': 0, 'actors': 0, 'force_unwraps': 0, 'weak_self_captures': 0, 'escaping_closures': 0, 'swiftui_state_objects': 0, 'swiftui_observed_objects': 0, 'async_awaits': 0 } def analyze_file(self, filepath: str): try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() lines = content.split('\n') except Exception as e: return {"file": filepath, "error": str(e), "issues": []} self.issues = [] for key in self.metrics: self.metrics[key] = 0 self.metrics['lines_of_code'] = len(lines) self._check_basic_syntax_and_oop(lines) self._check_memory_management(lines) self._check_concurrency(lines) self._check_swiftui_anti_patterns(lines) # 全局启发式逻辑推理 self._aggregate_heuristics() return { "file": filepath, "issues": self.issues, "metrics": self.metrics } def _strip_comments(self, line): idx = line.find('//') return line[:idx] if idx != -1 else line def _check_basic_syntax_and_oop(self, lines): for idx, line in enumerate(lines, 1): clean = self._strip_comments(line) if re.search(r'\bclass\b\s+[A-Za-z0-9_]+', clean): self.metrics['classes'] += 1 if re.search(r'\bstruct\b\s+[A-Za-z0-9_]+', clean): self.metrics['structs'] += 1 if re.search(r'\bactor\b\s+[A-Za-z0-9_]+', clean): self.metrics['actors'] += 1 # 暴力解包 `!` 查杀 if '!' in clean and '!=' not in clean and 'as!' in clean: self.metrics['force_unwraps'] += 1 # 这里忽略强制转换,只关注变量 ! if 'as!' in clean: self.issues.append({ "type": "safety", "severity": "WARNING", "message": "使用了不受控的强转 `as!`,如果类型不匹配将导致运行时崩溃 (Fatal Error)。请优先使用原生的 `if let value = obj as? Type`。", "line": idx }) def _check_memory_management(self, lines): for idx, line in enumerate(lines, 1): clean = self._strip_comments(line) if '[weak self]' in clean or '[unowned self]' in clean: self.metrics['weak_self_captures'] += 1 if '@escaping' in clean: self.metrics['escaping_closures'] += 1 def _check_concurrency(self, lines): for idx, line in enumerate(lines, 1): clean = self._strip_comments(line) if 'await ' in clean or 'async ' in clean: self.metrics['async_awaits'] += 1 if 'DispatchQueue.main.async' in clean: self.issues.append({ "type": "modernization", "severity": "INFO", "message": "检测到遗留的古老 GCD `DispatchQueue.main.async` 切换调用。在现代并发模型中,考虑使用 `@MainActor` 属性宏或者 `await MainActor.run { }` 替代。", "line": idx }) def _check_swiftui_anti_patterns(self, lines): for idx, line in enumerate(lines, 1): clean = self._strip_comments(line) if '@StateObject' in clean: self.metrics['swiftui_state_objects'] += 1 if '@ObservedObject' in clean: self.metrics['swiftui_observed_objects'] += 1 if re.search(r'@ObservedObject\s+(var|let)\s+[A-Za-z_]+\s*=\s*[A-Za-z_]+\(', clean): self.issues.append({ "type": "architecture", "severity": "CRITICAL", "message": "灾难性的 SwiftUI反模式:通过 `@ObservedObject` 实例化了一个 ViewModel/状态容器!它将在 SwiftUI 构建该视图块时被不断重制并丢失所有状态!你应该将其替换为 `@StateObject`。", "line": idx }) def _aggregate_heuristics(self): # 如果存在很多回调代码却少有弱化断环手段 if self.metrics['escaping_closures'] > 3 and self.metrics['weak_self_captures'] == 0: self.issues.append({ "type": "memory", "severity": "HIGH", "message": f"发现了大量逃逸闭包 ({self.metrics['escaping_closures']} 个),但在全文中未发现任何 `[weak self]` 捕获列表!这极大概率存在交叉引用导致类被封存(Retain Cycle)。请使用 Xcode Memory Graph 仔细排除泄漏。", "line": 0 }) # 使用入口 if __name__ == "__main__": import sys analyzer = SwiftAnalyzer() code = sys.stdin.read() print(json.dumps(analyzer.analyze_file("stdin"), indent=2, ensure_ascii=False)) ``` ## 企业级工具链与验证 (SwiftLint) 纯文本人工检索遗漏极大,应当使用由业界(如 Realm)维护的 `SwiftLint`: **在 Xcode Build Phase 中加入扫描钩子:** ```bash if which swiftlint >/dev/null; then swiftlint --strict # 严格模式,触发 warning 即编译失败阻止提交 else echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" fi ``` 并编写相应的 `.swiftlint.yml` 中严格禁绝使用 Force Casting (`as!`) 与 Force Tries (`try!`)。 ## 相关技能 - **kotlin** - 同步对比理解双轨原生世界的极高相似度理念。 - **performance-optimization** - 对移动端 GPU 刷新率及主线程卡顿的长效监控追踪策略。
View on GitHub