Swift編碼規范

以下是一些常見的Swift編碼規范,可以幫助保持代碼一致性、可讀性和可維護性。

1. 命名規范

  • 類名、結構體名、協議名:使用駝峰式命名(CamelCase),首字母大寫。例如:MyClassUserProfile
  • 變量名、函數名、參數名:使用駝峰式命名(camelCase),首字母小寫。例如:userNamecalculateArea()
  • 常量:使用駝峰式命名(camelCase),并且首字母小寫。例如:maximumNumberOfFiles

2. 代碼格式

  • 縮進:使用 4 個空格縮進,不要使用Tab。
  • 括號:左括號與關鍵詞保持同一行,右括號單獨占一行。例如:
    if condition {
        // code
    }
    
  • 換行:每行代碼最多80-100個字符。超長的表達式應在運算符前換行。
  • 空格:在關鍵字和括號之間留一個空格,例如 if (condition),而在函數調用中不應在函數名和左括號之間留空格,例如 calculateArea(width: 5)

3. 注釋

  • 使用//來寫單行注釋,使用/* ... */來寫多行注釋。
  • 注釋應該簡潔明了,解釋為什么做某些操作,而不是解釋“怎么做”。

4. 代碼組織

  • 屬性和方法的順序:通常將常量屬性放在最前面,變量屬性其次,然后是初始化方法(如構造函數),接著是其他方法。
  • 分組相關代碼:使用MARK:分隔符來分組相關功能的方法。例如:
    // MARK: - Lifecycle Methods
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    

5. 使用Self關鍵字

  • 只有在必要時使用self關鍵字,例如在閉包中捕獲self或參數名與屬性名沖突時。

6. 使用類型推斷

  • 能使用類型推斷時,盡量讓編譯器推斷類型。避免冗長的類型聲明。例如:
    let name = "John"  // 而不是 let name: String = "John"
    

7. 錯誤處理

  • 使用guard語句來提前退出錯誤情況,減少嵌套。
  • 使用do-catch來處理可能拋出錯誤的代碼。

8. Optionals

  • 使用if letguard let來安全解包optional值。
  • 使用??操作符提供默認值,避免解包失敗。

9. 集合和字面量

  • 使用簡潔的字面量語法,例如[]表示空數組,[:]表示空字典。
  • 使用for-in循環來遍歷數組、字典或其他集合。

10. 遵循協議的實現

  • 遵循協議的函數應該盡量放在一個extension中,使主類定義保持簡潔。

11. 訪問控制

  • 適當使用privatefileprivateinternalpublicopen來控制屬性和方法的可見性,默認使用最低可見性。

12. 避免強制解包

  • 避免使用!來強制解包Optional變量,除非你明確知道它不會為nil。

13. 空數組和字典的初始化

  • 使用簡潔的初始化語法:
    var names = [String]()
    var scores = [String: Int]()
    

14. 避免全局變量

  • 除非必要,避免使用全局變量。盡量在類或結構體內定義屬性。

15. 命名文件

  • 文件名應與類、結構體或協議的名稱一致。

16. 使用 Final 關鍵字

  • 在類、方法或屬性前加上final關鍵字,防止它們被繼承或重寫,除非確實需要繼承行為。這樣可以提高性能并增加代碼的安全性。

17. 盡量使用 Swift 標準庫的功能

  • 使用Swift標準庫提供的功能而不是自己實現。例如,使用mapfilterreduce等高階函數來操作數組,而不是手動實現循環。

18. 避免過度使用嵌套

  • 復雜的嵌套結構會使代碼難以理解。使用guard語句、早返回、分解函數和邏輯來減少嵌套層級。

19. 處理返回值

  • 如果函數有返回值,在需要的情況下捕獲和使用它們。避免調用函數但忽略其返回值的情況。

20. 內存管理

  • 小心處理強引用循環,特別是在閉包中使用[weak self][unowned self]來避免強引用循環。
  • 理解ARC(自動引用計數)的工作原理,確保對象在不需要時被釋放。

21. 使用Enums而不是Magic Numbers

  • 使用enum代替硬編碼的常量或“魔法數字”。這樣可以使代碼更具可讀性和可維護性。
enum UserType {
    case admin
    case regular
    case guest
}

22. 遵循 SOLID 原則

  • 盡量遵循面向對象設計的SOLID原則:單一職責原則、開閉原則、里氏替換原則、接口分離原則和依賴反轉原則。這有助于使代碼模塊化、可擴展和易于維護。

23. 避免過長的函數

  • 函數應盡量短小,只執行單一職責。如果函數過長,考慮將其拆分為多個函數。

24. 使用合適的集合類型

  • 根據需求選擇合適的集合類型(如ArraySetDictionary)。例如,如果不需要元素順序且需要唯一性,使用Set

25. 使用字符串插值而非拼接

  • 使用字符串插值"\(variable)"而不是使用+運算符來拼接字符串,這樣更簡潔和高效。

26. 處理可選值時使用 Nil-Coalescing 操作符

  • 使用??提供默認值,以便在可選值為nil時使用默認值。
let value = optionalValue ?? "default value"

27. 類型別名

  • 當類型復雜且多次使用時,使用typealias為類型創建別名,增加代碼可讀性。
typealias CompletionHandler = (Result<Data, Error>) -> Void

28. Documentation(文檔注釋)

  • 使用///語法為公共API、類、方法和屬性編寫文檔注釋,以便生成文檔并幫助其他開發人員理解代碼。
/// 計算矩形的面積
/// - Parameters:
///   - width: 矩形的寬度
///   - height: 矩形的高度
/// - Returns: 矩形的面積
func calculateArea(width: Double, height: Double) -> Double {
    return width * height
}

29. 避免大塊的代碼注釋

  • 如果某些代碼不再使用,考慮刪除而不是注釋掉。版本控制系統如Git可以幫助跟蹤代碼的歷史。

30. 定義初始化方法

  • 自定義的初始化方法應確保所有屬性都被正確初始化。使用convenience initrequired init根據需要定義多種初始化方式。

31. 盡量避免使用全局函數

  • 盡量避免使用全局函數,除非這些函數與具體類型無關。使用靜態方法或擴展來組織代碼。

32. 類與結構體的選擇

  • 使用結構體(struct)而非類(class),當數據是值類型且不會被繼承時。結構體是默認不可變的,可以減少錯誤。

33. 保持一致性

  • 保持代碼風格的一致性。團隊成員之間應采用統一的編碼風格,以便不同的人可以輕松理解和維護代碼。

34. 自動化工具和Linting

  • 使用工具如SwiftLint來自動檢查代碼風格一致性和潛在錯誤。自動化工具可以幫助發現并遵循規范。

35. 性能優化

  • 使用lazy關鍵字延遲初始化,減少不必要的性能開銷。
  • 只在必要時使用@escaping關鍵字來避免閉包導致的引用循環。

36. 保持接口簡單

  • 盡量保持函數和方法的參數數量少于5個。過多的參數會增加函數的復雜性和使用難度。可以考慮使用結構體來傳遞多個參數。

37. 使用可變參數 (Variadic Parameters)

  • 當需要傳遞可變數量的相同類型參數時,使用可變參數。例如,定義一個函數可以接受多個字符串:
func logMessages(_ messages: String...) {
    for message in messages {
        print(message)
    }
}

38. 避免使用 Any 和 AnyObject

  • 盡量避免使用AnyAnyObject,除非絕對必要。明確的類型更容易理解和調試,使用泛型來保持類型安全。

39. 延遲屬性初始化

  • 使用lazy關鍵字來延遲初始化那些可能在對象生命周期中不一定會用到的屬性,從而提高性能:
lazy var expensiveObject: ExpensiveObject = {
    // 初始化代碼
    return ExpensiveObject()
}()

40. 使用 defer 語句

  • 使用defer語句來確保在函數或方法退出前執行特定的清理操作,如關閉文件或釋放資源。這在資源管理或處理錯誤時非常有用。
func readFile() {
    let file = openFile()
    defer {
        closeFile(file)
    }
    // 文件處理代碼
}

41. 盡量避免強制類型轉換 (Forced Casting)

  • 強制類型轉換使用as!是不安全的,可能導致運行時崩潰。使用可選綁定(as?)或條件類型檢查(if let)來處理轉換。

42. 避免使用魔術字符串 (Magic Strings)

  • 不要在代碼中直接使用字符串字面量作為標識符、鍵名或配置選項。使用常量或枚舉來定義這些值,以減少拼寫錯誤和維護難度。

43. 使用閉包簡寫語法

  • 當閉包參數名稱沒有歧義時,使用Swift的閉包簡寫語法來使代碼更簡潔:
let sortedNames = names.sorted { $0 > $1 }

44. 測試和單元測試

  • 編寫單元測試來驗證代碼的正確性。使用XCTest框架來編寫和運行測試。確保覆蓋關鍵路徑和邊界情況。

45. 優化UI代碼

  • 使用DispatchQueue.main.async確保UI更新在主線程上進行。
  • 在重繪和布局變化頻繁的地方,如tableViewcollectionView的cell中,避免復雜的計算或數據處理。

46. 使用 Functional Programming Paradigms

  • 盡量使用Swift的函數式編程功能,如mapfilterreduce,而不是傳統的循環。這可以使代碼更簡潔并減少錯誤。

47. 在對象創建時使用構造函數依賴注入

  • 通過構造函數傳遞依賴項而不是使用全局單例或依賴查找。這可以使對象更容易測試和復用。
class ViewController: UIViewController {
    private let dataService: DataService

    init(dataService: DataService) {
        self.dataService = dataService
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

48. 使用guard提高代碼可讀性

  • guard語句比if更適合用于條件提前退出,避免深度嵌套,并使代碼更扁平化和易讀。
func process(value: Int?) {
    guard let value = value else {
        return
    }
    // 使用 value 進行處理
}

49. 處理異步代碼時使用 Task 和 await

  • Swift 5.5 引入了并發功能。使用async/await處理異步操作,這比傳統的回調和閉包更易于理解和管理。
func fetchData() async throws -> Data {
    let data = try await URLSession.shared.data(from: url)
    return data
}

50. 使用擴展 (Extensions)

  • 使用擴展將相關的功能或特性分組,使代碼更有組織性。將協議實現和特定功能分離到各自的擴展中。
extension User {
    func fullName() -> String {
        return "\(firstName) \(lastName)"
    }
}

51. 使用自定義操作符時保持謹慎

  • 自定義操作符可能會使代碼更簡潔,但過度使用或命名不清晰可能導致混淆。確保它們有明確的含義并與標準操作符一致。

52. 考慮可讀性和維護性

  • 在代碼優化和簡化時,始終優先考慮可讀性。寫給其他開發者看的代碼應該是清晰和易于理解的。

53. 正確處理 UI 狀態

  • 避免直接操作 UI 組件的狀態,特別是在多線程環境中。使用專門的狀態管理工具或模式(如Redux、MVVM)來管理狀態和視圖更新。

54. 合理使用數據封裝和隱私

  • 盡量將屬性和方法設為privatefileprivate,只有在需要時才暴露為internalpublic。這有助于防止對象被意外修改。

55. 避免過度優化

  • 先讓代碼可讀和工作正常,然后根據性能需求進行優化。過早的優化可能會增加復雜性并難以維護。

56. 使用訪問控制明確表達意圖

  • 訪問控制不僅僅是為了安全性,它也表達了類、屬性或方法的意圖。使用privatefileprivateinternalpublicopen來明確哪些部分應該被訪問或繼承。

57. 使用typealias簡化復雜類型

  • 當使用復雜類型時,例如閉包或元組,使用typealias可以提高可讀性和易用性。
typealias CompletionHandler = (Result<Data, Error>) -> Void

58. 適當使用deinit進行清理

  • 在類中實現deinit方法,用于釋放資源或進行必要的清理操作,避免內存泄漏或其他資源問題。

59. 避免無用的代碼

  • 定期清理不再使用的代碼、變量、函數和文件。保持代碼庫的簡潔和整潔,有助于提高項目的可維護性。

60. 合理使用@available#available檢查系統版本

  • 在處理不同iOS版本兼容性時,使用@available注解和#available語句來檢查API的可用性。
if #available(iOS 15, *) {
    // 使用 iOS 15 的新特性
} else {
    // 使用兼容版本的實現
}

61. 使用@discardableResult修飾符

  • 如果函數返回值不一定需要處理,但你仍希望函數有返回值,可以使用@discardableResult來標記,以避免編譯器警告。
@discardableResult
func performTask() -> Bool {
    // 執行任務
    return true
}

62. 避免使用嵌套的guardif語句

  • 當使用guardif語句時,盡量避免嵌套。過多的嵌套會使代碼難以閱讀和理解。使用早退出的方式可以簡化邏輯。

63. 避免過度使用單例模式

  • 雖然單例模式有其用途,但過度使用會增加代碼的耦合性和測試的難度。只在需要全局共享狀態時使用單例。

64. 在適當時使用@frozen關鍵字

  • 對于不希望在未來擴展或修改的enumstruct使用@frozen關鍵字。這能提高優化和性能。
@frozen
enum Direction {
    case north
    case south
    case east
    case west
}

65. 遵循命令查詢分離原則 (Command Query Separation, CQS)

  • 將命令(改變狀態的方法)與查詢(返回信息的方法)分離。一個方法要么是做事(有副作用),要么是返回值(無副作用),而不是兩者都做。

66. 正確處理多線程

  • 使用GCD(Grand Central Dispatch)和OperationQueue來管理多線程操作。確保UI更新總是在主線程上進行,并避免數據競爭和死鎖。

67. 使用mapflatMapcompactMapreduce等函數

  • 這些函數可以使集合操作更簡潔和表達力更強。例如,將一個可選數組中的所有非nil值提取出來:
let numbers: [Int?] = [1, 2, nil, 4, nil]
let nonNilNumbers = numbers.compactMap { $0 }

68. 盡量避免在init方法中調用方法

  • 調用子類或自身的可被重寫的方法可能導致未定義的行為,因為對象可能尚未完全初始化。

69. 使用協議而不是繼承

  • 如果不需要共享具體實現細節,使用協議來定義接口而不是繼承。這樣可以減少耦合,提高靈活性和復用性。

70. 在擴展中實現協議

  • 將協議的實現放在擴展中,而不是在類定義中,這可以保持類定義的簡潔和清晰。
class User: Codable {
    var name: String
}

extension User: CustomStringConvertible {
    var description: String {
        return "User(name: \(name))"
    }
}

71. 對大數組或集合的操作使用懶序列

  • 使用lazy屬性來實現延遲求值,有助于提高性能,尤其是在處理大型集合時。
let largeArray = Array(1...1000).lazy.filter { $0 % 2 == 0 }.map { $0 * 2 }

72. 處理defer中的錯誤

  • defer語句塊中處理可能的錯誤情況,這樣可以確保在方法退出前執行必要的清理操作,即使出現了錯誤。
func processFile() {
    let file = openFile()
    defer {
        closeFile(file)
    }
    // 其他文件操作
}

73. 避免不必要的可變狀態

  • 盡量使用let而不是var,減少狀態的可變性。這有助于代碼更加穩定和可靠。

74. 合理使用default分支

  • 在處理enum或其他明確類型時,盡量避免使用default分支,而是明確列出每種情況,以便在新增類型時可以發現編譯錯誤。

75. 使用#warning#error標簽標記待辦事項

  • 使用#warning("To-Do: refactor this method")來標記需要進一步改進的代碼,以提醒開發者后續處理。

76. 多使用Swift內建的調試工具

  • 善用Xcode的調試工具、儀器(Instruments)、性能分析工具(如Time Profiler)來監控和優化代碼。

77. 使用@objc時的注意事項

  • 僅在需要與Objective-C互操作時使用@objc,這將影響性能并增加復雜性。

78. 避免魔法方法

  • 不要過度依賴于特殊命名的魔法方法,例如viewDidLoadviewWillAppear。雖然它們在特定框架中有特定意義,但過度使用或在自定義類中定義類似方法可能會導致混淆。

79. 優化內存使用

  • 使用弱引用(weak)或無主引用(unowned)來避免強引用循環,特別是在視圖控制器和其視圖模型之間。

80. 使用自定義日志功能

  • 使用自定義日志方法或框架來替代print,這樣可以更好地控制日志級別(如Debug、Info、Warning、Error)并更方便地在生產環境中啟用或禁用日志。

總結

這些附加的Swift編碼規范和最佳實踐幫助提升代碼的安全性、可維護性和性能。遵循這些準則可以使代碼更加清晰、易讀、易于調試,并減少潛在的錯誤風險。在項目開發中,始終保持良好的編碼習慣不僅能夠提高代碼質量,還能促進團隊協作和項目的長期可持續性。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • 溫德里奇規范 本規范原文鏈接. 規范只是一些最佳實踐, 請酌情使用. 1 正確性 第一條原則, 也是最根本的原則:...
    貘鳴閱讀 1,593評論 1 0
  • Swift 編碼規范 基本原則 參考資料 通用規則 格式 命名 編碼風格 訪問修飾符 Enum Optional ...
    wsj_2012閱讀 2,018評論 0 4
  • 翻譯作者:碼農網 – 豆照建 沒事多看看,規范一下swift 編碼習慣。 1. 代碼格式 1.1 使用四個空格進行...
    彡廿閱讀 848評論 0 2
  • 官方 Swift 風格指南 一定要閱讀Apple 的 API 設計規范。 具體的規范細節和附加說明如下。 本指南已...
    蘋果上的小豌豆閱讀 731評論 0 1
  • 注:以下皆為翻譯,如有錯誤或疏漏,請指正。謝謝? 簡介 (raywenderlich 版)您看到的這份規范可能與其...
    LovelyYilia閱讀 4,430評論 1 17