Swift中的代码审查:检查什么以及如何提供反馈
代码审查不仅仅是一种形式,更是提升代码质量、在团队内部分享知识以及预防错误的强大工具。然而,如果审查流于形式,或者过于激进,反而可能弊大于利。本文将详细分析在审查iOS和macOS的Swift代码时,具体需要关注哪些方面,以及如何表述反馈意见,使其既有帮助又不伤害同事。
1. 架构与设计:从根源审视
在深入实现细节之前,先评估解决方案的整体架构。好的代码不仅关乎语法,更关乎结构。
- 单一职责原则 (SRP): 类/函数是否试图做太多事情?例如,ViewController是否混合了业务逻辑和网络请求?
- MVVM / MVC / VIPER: 代码是否符合所选模式?如果项目使用MVVM,那么ViewModel不应导入
UIKit。 - 依赖管理: 是否使用了依赖注入 (DI) 还是在内部创建对象?硬依赖会增加测试难度。
- 内存管理: 是否存在内存泄漏?检查
@escaping闭包、对self的强引用以及可能的循环引用。
// 不好:闭包中对self的强引用class NetworkManager { var onComplete: (() -> Void)?
func fetchData() { URLSession.shared.dataTask(with: URL(string: "https://api.example.com")!) { data, _, _ in self.onComplete?() // 内存泄漏!闭包持有对self的强引用 }.resume() }}
// 好:使用 [weak self]class NetworkManager { var onComplete: (() -> Void)?
func fetchData() { URLSession.shared.dataTask(with: URL(string: "https://api.example.com")!) { [weak self] data, _, _ in DispatchQueue.main.async { self?.onComplete?() } }.resume() }}2. 类型安全与可选性:利用Swift的强大功能
Swift是一种强类型语言,代码审查应体现这一点。避免编写“披着Swift外衣的ObjC代码”。
- 强制解包: 是否存在可以避免的
!?请使用guard let或if let。 - 枚举 (Enums): 是否使用枚举代替字符串常量?例如,用于响应状态或错误类型。
- Result类型: 是否通过
Result<Success, Failure>处理错误,而不是返回可选值和一个单独的错误? - 泛型: 泛型的使用是否恰当?有时它们会不必要地使代码复杂化。
// 不好:强制解包和字符串常量func getUser(id: String!) -> User? { if id == "admin" { return User(name: "Admin") } return nil}
// 好:使用枚举和安全解包enum UserType: String { case admin case regular}
func getUser(id: String?) -> User? { guard let userId = id, let userType = UserType(rawValue: userId) else { return nil } // ... 逻辑 return User(name: userType.rawValue)}3. 性能与UI操作:保护电池与帧率
对于iOS/macOS应用,动画流畅度和能效至关重要。请关注:
- 主线程: 所有UI更新都应在主线程进行。检查是否从后台队列调用了
UIView或NSView。 - 繁重计算: 是否在执