用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/microwind/ai-skills --skill swift命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | Swift 分析大师与苹果生态架构指南 |
| description | 专为 iOS/macOS 现代开发打造的代码分析规范。全面剖析 SwiftUI 响应式模式、ARC 强引用循环破除、以及 Swift 5.5+ 下基于 Actor 与 async/await 的全新并发架构。 |
| license | MIT |
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 只做驱动模型状态的反射。
始终:
@escaping 闭包和 NotificationCenter 的陈旧代码库。SwiftUI 响应式视图体系。触发短语:
self.method() 导致的隐式强捕获,强制提醒并重构为 [weak self] 或 [unowned self]。@propertyWrapper 或 weak 修饰的 Delegate 指针,导致子控制器锁死父控制器的释放链。struct 是按值传递(Copy-on-Write)。检测在集合或大型状态容器中引发隐式全量深拷贝的低效操作。DispatchQueue.main.async 并指导迁移向更为线笥的 await MainActor.run。Sendable 协议要求,以及非线程安全的 Class 是否需要重构为 actor 以保证内部状态互斥。@State 到子视图导致整个 View 树雪崩式重建重绘的问题。@ObservedObject 误当做状态根拥有者(它会在 View 的重建时被无情摧毁丢失状态),必须替换为 @StateObject (iOS 14) 或 @State (iOS 17 Observation 框架)。问题:
在网络请求或延时任务的闭包中,隐式或显式地持有了 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
}
}
问题:
过时的 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
}
问题:
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 特有的 weak self 及复杂的特有标记(@State, @MainActor),在实际业务中能产生巨大的排雷作用。
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 = []
key .metrics:
.metrics[key] =
.metrics[] = (lines)
._check_basic_syntax_and_oop(lines)
._check_memory_management(lines)
._check_concurrency(lines)
._check_swiftui_anti_patterns(lines)
._aggregate_heuristics()
{
: filepath,
: .issues,
: .metrics
}
():
idx = line.find()
line[:idx] idx != - line
():
idx, line (lines, ):
clean = ._strip_comments(line)
re.search(, clean):
.metrics[] +=
re.search(, clean):
.metrics[] +=
re.search(, clean):
.metrics[] +=
clean clean clean:
.metrics[] +=
clean:
.issues.append({
: , : ,
: ,
: idx
})
():
idx, line (lines, ):
clean = ._strip_comments(line)
clean clean:
.metrics[] +=
clean:
.metrics[] +=
():
idx, line (lines, ):
clean = ._strip_comments(line)
clean clean:
.metrics[] +=
clean:
.issues.append({
: , : ,
: ,
: idx
})
():
idx, line (lines, ):
clean = ._strip_comments(line)
clean:
.metrics[] +=
clean:
.metrics[] +=
re.search(, clean):
.issues.append({
: , : ,
: ,
: idx
})
():
.metrics[] > .metrics[] == :
.issues.append({
: , : ,
: ,
:
})
__name__ == :
sys
analyzer = SwiftAnalyzer()
code = sys.stdin.read()
(json.dumps(analyzer.analyze_file(), indent=, ensure_ascii=))
纯文本人工检索遗漏极大,应当使用由业界(如 Realm)维护的 SwiftLint:
在 Xcode Build Phase 中加入扫描钩子:
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!)。