一、先明確:什麼是 iOS 中的 "垃圾代碼"?
- 代碼冗餘:重複的 UI 配置、網絡請求、數據解析邏輯散落在各處;
- 耦合嚴重:ViewController 動輒上千行,既管 UI、又管業務、還管數據;
- 命名混亂:變量名用
temp/data/btn1,方法名無語義(如func doSomething()); - 忽視邊界:無空值判斷、無異常捕獲,容易崩潰;
- 性能低下:頻繁刷新 UI、不合理的緩存、主線程做耗時操作;
- 可測性差:代碼緊耦合,無法單獨單元測試。
二、編碼規範:從基礎層面規避垃圾代碼
1. 命名:見名知意,遵循 iOS 生態規範
- 遵循 Apple 命名習慣:
- 類名:大駝峯(
UserProfileViewController),避免拼音 / 縮寫(除非是通用縮寫如VC/VM); - 方法名:小駝峯 + 動詞開頭(
func fetchUserInfo()/func updateAvatar(),而非func getUser()/func doAvatar()); - 變量名:小駝峯 + 語義化(
userNickname而非name,loginButton而非btn1); - 常量名:全大寫 + 下劃線分隔(
static let MAX_LOGIN_RETRY_COUNT = 3)。
- 避免歧義:比如
data要明確是userListData/productDetailData,result要明確是loginResult/requestResult。
2. 格式:統一風格,提升可讀性
- 用 Xcode 自帶的格式化工具(
Ctrl+I),保證縮進、空格、換行統一; - 閉包 / 方法體超過 3 行時,拆分行書寫(比如 Then 庫的配置閉包,每行一個屬性);
- 註釋只寫 "為什麼",不寫 "做什麼"(代碼本身能説明做什麼,比如:
swift
// 錯誤:設置按鈕顏色
btn.backgroundColor = .red
// 正確:主按鈕使用品牌紅色,符合設計規範v2.1
btn.backgroundColor = .brandRed
3. 語法:用 Swift 現代語法替代冗餘寫法
- 用擴展(Extension) 拆分大類:將 ViewController 的代理、點擊事件、UI 配置拆到不同 Extension 中;
swift
// 原垃圾代碼:所有邏輯堆在ViewController裏
// 優化:拆分成Extension
extension UserVC: UITableViewDelegate { ... } // 代理邏輯
extension UserVC { // UI配置邏輯
func setupUI() { ... }
}
extension UserVC { // 網絡請求邏輯
func fetchData() { ... }
}
- 用可選鏈 + 空合運算符 替代嵌套 if-let:
swift
// 垃圾代碼
if let user = currentUser {
if let avatar = user.avatar {
imageView.image = avatar
} else {
imageView.image = defaultAvatar
}
} else {
imageView.image = defaultAvatar
}
// 優化
imageView.image = currentUser?.avatar ?? defaultAvatar
- 用枚舉替代魔法值:
swift
// 垃圾代碼:魔法值散落在各處
if status == 1 { ... } else if status == 2 { ... }
// 優化:枚舉封裝
enum OrderStatus: Int {
case pending = 1
case paid = 2
case shipped = 3
}
if let status = OrderStatus(rawValue: statusInt), status == .pending { ... }
三、架構設計:從結構上避免代碼混亂
1. 分層設計:每個組件只做一件事
|
組件
|
職責(只做這些事)
|
禁止做的事
|
|
View
|
純 UI 展示、響應點擊(UIView/ViewController)
|
處理業務邏輯、請求網絡
|
|
ViewModel
|
處理業務邏輯、轉換數據(View←→Model)
|
持有 View、直接操作 UI
|
|
Model
|
數據模型(結構體 / 類)、數據驗證
|
包含業務邏輯、網絡請求
|
|
Service
|
網絡請求、本地存儲(CoreData/Keychain)
|
處理 UI 邏輯、業務判斷
|
|
Router
|
頁面跳轉(可選)
|
處理業務邏輯、持有 View
|
swift
// 垃圾代碼:VC既請求數據,又處理邏輯,又更新UI
class UserVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 網絡請求(不該在VC裏)
URLSession.shared.dataTask(with: URL(string: "xxx")!) { data, _, _ in
let user = try! JSONDecoder().decode(User.self, from: data!)
// 業務邏輯(不該在VC裏)
let showName = user.nickname ?? user.phone
// 更新UI(該在VC裏,但邏輯太雜)
DispatchQueue.main.async {
self.nameLabel.text = showName
}
}.resume()
}
}
// 優化:MVVM拆分
// 1. Model:純數據
struct User: Codable {
let nickname: String?
let phone: String
}
// 2. Service:網絡請求
class UserService {
func fetchUser(completion: @escaping (User?) -> Void) {
URLSession.shared.dataTask(with: URL(string: "xxx")!) { data, _, _ in
guard let data = data else { completion(nil); return }
let user = try? JSONDecoder().decode(User.self, from: data)
completion(user)
}.resume()
}
}
// 3. ViewModel:業務邏輯
class UserVM {
let service = UserService()
var userName: String = ""
func loadUser(completion: @escaping () -> Void) {
service.fetchUser { [weak self] user in
guard let self = self, let user = user else {
self?.userName = "未知用户"
completion()
return
}
// 業務邏輯:處理顯示名稱
self.userName = user.nickname ?? user.phone
completion()
}
}
}
// 4. ViewController:只負責UI
class UserVC: UIViewController {
let vm = UserVM()
let nameLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
loadData()
}
func setupUI() { /* 只配置UI,無業務邏輯 */ }
func loadData() {
vm.loadUser { [weak self] in
DispatchQueue.main.async {
self?.nameLabel.text = self?.vm.userName
}
}
}
}
2. 複用邏輯:封裝成工具類 / 擴展
- 通用 UI 配置:封裝成
UIView+Extension(比如按鈕圓角、文字樣式); - 網絡請求:封裝成
NetworkManager單例(統一處理請求頭、超時、錯誤); - 數據解析:封裝成
Model+Decode(統一處理 JSON 解析、默認值); - 常用工具:封裝成
Utils(比如日期格式化、字符串加密)。
四、工程實踐:用流程和工具約束代碼質量
1. 強制代碼檢查
- 集成SwiftLint:通過規則配置(
.swiftlint.yml)強制遵守命名、格式、語法規範,比如禁止使用force unwrap(!)、禁止空註釋;
- 安裝:
brew install swiftlint; - 配置:在 Xcode Build Phases 中添加腳本,每次編譯自動檢查,違規則編譯失敗;
- 集成Infer:靜態分析工具,檢測空指針、內存泄漏、資源未釋放等問題。
2. 單元測試:驗證代碼正確性
- 對 ViewModel、Service、工具類編寫單元測試(XCTest),覆蓋核心業務邏輯;
- 目標:核心代碼的測試覆蓋率≥80%,避免 "改一處崩全量";
- 示例:測試 UserVM 的業務邏輯
swift
import XCTest
@testable import YourApp
class UserVMTest: XCTestCase {
func testUserName() {
// 測試暱稱非空時,顯示暱稱
let user = User(nickname: "張三", phone: "13800138000")
let vm = UserVM()
vm.user = user
XCTAssertEqual(vm.userName, "張三")
// 測試暱稱為空時,顯示手機號
let user2 = User(nickname: nil, phone: "13800138000")
vm.user = user2
XCTAssertEqual(vm.userName, "13800138000")
}
}
3. 避免常見坑點
- 內存泄漏:用
weak self避免閉包循環引用,用 Instruments 的 Leaks 工具檢測; - 主線程阻塞:所有耗時操作(網絡、數據庫、圖片解碼)放到子線程,用
DispatchQueue.global().async; - 過度封裝:不要為了封裝而封裝(比如一個簡單的按鈕點擊,沒必要拆成多個類);
- 忽視版本兼容:用
if #available(iOS 15.0, *)判斷系統版本,避免低版本崩潰; - 硬編碼:所有字符串(文案、接口地址)、數值(尺寸、超時時間)放到
Constants常量類中。
五、團隊協作:統一標準,持續優化
- 制定團隊編碼規範文檔:明確命名、格式、架構、註釋的統一標準;
- 代碼 Review:提交代碼前必須經過 Review,重點檢查耦合、冗餘、邏輯漏洞;
- 定期重構:每迭代 1-2 個版本,重構一次核心模塊的垃圾代碼(小步快跑,避免技術債堆積);
- 學習 Apple 官方示例:參考 Apple 的 Sample Code(如 SwiftUI 示例、MVVM 示例),對齊官方最佳實踐。