원클릭으로
swift
专为 iOS/macOS 现代开发打造的代码分析规范。全面剖析 SwiftUI 响应式模式、ARC 强引用循环破除、以及 Swift 5.5+ 下基于 Actor 与 async/await 的全新并发架构。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
专为 iOS/macOS 现代开发打造的代码分析规范。全面剖析 SwiftUI 响应式模式、ARC 强引用循环破除、以及 Swift 5.5+ 下基于 Actor 与 async/await 的全新并发架构。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
在DDD中具有唯一身份标识和生命周期的对象,通过身份而非属性值相等判断。
封装复杂对象和聚合的创建过程,将创建职责从领域对象中剥离,保证聚合创建时的不变量满足。
没有身份标识,通过属性值判断相等的对象。不可变,通常代表领域中的度量或描述。
命令查询责任分离,将数据的写入操作和读取操作分别用不同的模型处理,优化各自的性能。
将DDD战略设计应用于微服务架构,限界上下文指导服务拆分,领域事件实现服务间通信。
| 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": []}
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))
纯文本人工检索遗漏极大,应当使用由业界(如 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!)。