天天看點

Swift 4.0 編碼規範,持續更新中...(已更新Swift 5.0)

自Swift 3.0 以來,語言已經比較成熟,用Swift語言來開發iOS App 的開發者越來越多,那麼一份權威而全面的規範就很有必要了。蘋果官方的文檔有時間大家還是多看看,筆者參考官方文檔和各路大神的經驗,寫下了一份基于Swift 4.0 的編碼規範,并會持續更新,歡迎大家補充指正。

文章目錄

      • 1. 編碼格式
      • 2. 命名規範
      • 3. 文法規範
      • 4. Swift 4.2 新特性
      • 5. Swift 5.0 新特性

1. 編碼格式

1.1 使用二進制運算符(+, -,==, 或->)的前後都需要添加空格

let value = 1 + 2
           

1.2 在逗号後面加一個空格

let titleArray = [1, 2, 3, 4, 5]
           

1.3 方法的左大括号不要另起,并和方法名之間留有空格,注釋空格

// function Define
func myFunction {
    // 處理
}
           

1.4 判斷語句不用加括号

if typeValue == 1 {
    // 處理
}
           

1.5 盡量不使用self. 除非方法參數與屬性同名

func setPerson(name: String, pAge: Int) {
    self.name = name
    age = pAge
}
           

1.6 在通路枚舉類型時,使用更簡潔的點文法

enum Direction {
    case north
    case south
    case east
    case west
}
let currentDirection = .west
           

1.7 添加有必要的注釋,盡可能使用Xcode注釋快捷鍵(⌘⌥/)

/// <#Description#>
///
/// - Parameters:
///   - tableView: <#tableView description#>
///   - section: <#section description#>
/// - Returns: <#return value description#>
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dataList.count
}
           

1.8 使用 // MARK: -,按功能、協定、代理等分組

// MARK: - UITableViewDelegate

// MARK: - Action

// MARK: - Request
           

1.9 協定一緻性:當對象要實作協定一緻性時,推薦使用 extension 隔離協定中的方法集,這樣讓相關方法和協定集中在一起,友善歸類和查找

// MARK: - UICollectionViewDelegate, UICollectionViewDataSource
extension XMHomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
	// 代理方法
}

// MARK: - HttpsRequest
extension XMHomeViewController {
	// 網絡請求方法
}
           

1.10 當對外接口不相容時,使用@available(iOS x.0, *) 标明接口适配的起始系統版本号

@available(iOS 8.0, *)
func myFunction() {
    //
}
           

2. 命名規範

2.1 常量,變量,函數,方法的命名規則使用小駝峰規則,首字母小寫,類型名使用大駝峰規則,首字母大寫。

class MyClass: class {
    let myImageView: UIImageView
    let myName: String
}
           

2.2 當命名裡出現縮寫詞時,縮寫詞要麼全部大寫,要麼全部小寫,以首字母大小寫為準

let htmlString = "https://www.baidu.com"
let urlString:  URLString
let userID:  UserID

class HTMLModel {
    //
}
           

2.3 bool類型命名時,使用is作為字首

var isMine: Bool = false
           

2.4 Swift中類别(類,結構體)在編譯時會把子產品設定為預設的命名空間,是以不用為了區分類别而添加字首,比如XYHomeViewController,但是為了和引用的第三方庫作區分,建議可以繼續使用字首,以作為規範化處理,結構更清晰。

2.5 懶加載用來細緻地控制對象的生命周期,這對于想實作延遲加載視圖的UIViewController特别有用

// MARK: - 懶加載
private lazy var tableView: UITableView = {
    let tableView = UITableView.init(frame: CGRect.zero, style: .plain)
    tableView.separatorStyle = .none
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 200
    tableView.dataSource = self
    tableView.delegate = self
    tableView.register(UINib(nibName: homeListCell, bundle: nil), forCellReuseIdentifier: homeListCell)
    return tableView
}()
           

2.6 當函數的第一個參數構成整個語句的介詞時(如,at, by, for, in, to, with 等),為第一個參數添加介詞參數标簽

func login(with username: String?, password: String?) {
	//
}
           

3. 文法規範

3.1 可選類型拆包取值時,使用if let 判斷

if let data = result.data {
    //
}
           

3.2 多個可選類型拆包取值時,将多個if let 判斷合并

if let name = person.name, let age = person.age {
    //
}
           

3.3 盡量不要使用 as! 或 try!,對于可選類型Optional多使用as?,?? 可以給變量設定預設值

// 使用if let as?判斷
if let name = person.name as? String {
    //
}
// 給name變量設定預設值
var name = person.name ?? ""
           

3.4 數組和字典變量定義時需要标明泛型類型,并使用更簡潔清晰的文法

var names: [String] = []
var values: [String: Int] = [:]
var person: [String: Any] = [:]
           

3.5 常量定義,建議盡可能定義在類型裡面,避免污染全局命名空間,如果是其他地方有可能複用的cell可以定義在類型外面

static let homeListCell = "HomeListCell"

class HomeListCell: UITableViewCell {
    static let kHomeCellHeight = 80.0
    //
}
           

3.6 當方法最後一個參數是Closure類型,調用時建議使用尾随閉包文法

UIView.animateWithDuration(1.0) {
     self.myView.alpha=0
}
           

3.8 最短路徑規則:當編碼遇到條件判斷時,左邊的距離是黃金路徑或幸福路徑,因為路徑越短,速度越快。guard 就為此而生的。

func login(with username: String?, password: String?) throws -> LoginError {
  guard let username = username else { 
    throw .noUsername 
  }
  guard let password = password else { 
    throw .noPassword
  }
  // 處理登入
}
           

3.9 循環周遊使用for-in表達式

// 循環
for _ in 0..<list.count {
  print("items")
}
// 周遊
for(index, person) in personList.enumerate() {
    print("\(person)is at position #\(index)")
}
// 間隔2位循環
for index in 0.stride(from: 0, to: items.count, by: 2) {
  print(index)
}
// 翻轉
for index in (0...3).reverse() {
    print(index)
}
           

4. Swift 4.2 新特性

4.1 CaseIterable協定:定義的枚舉遵循CaseIterable協定後,編譯時Swift 會自動合成一個allCases屬性,是包含枚舉的所有case項的數組

enum NetState: CaseIterable {
    case wifi
    case hotWifi
    case mobile
    case none
}
for item in NetState.allCases {
    print(item)
}
           

4.2 #warning 主要用于标記一些工作還沒有完成或者需要完善,Xcode 會發出一個警告;#error 标記錯誤,Xcode 會發出一個編譯錯誤這樣你的代碼就完全不能編譯

#warning("清單重新整理需要優化")

#if os(macOS)
#error("MyLibrary is not supported on macOS.")
#endif
           

4.3 新增 allSatisfy():一種檢查序列中的所有元素是否滿足條件的新方法

// 判斷數組的所有元素是否全部大于80
let scores = [86, 88, 95, 92]
// 傳回一個BOOL
let passed = scores.allSatisfy({ $0 > 80 })
print(passed)
// 輸出:true
           

4.4 新增 last(where:) 和 lastIndex(where:) 方法來擷取數組中滿足條件的最後的元素和索引值

let a = [10, 20, 30, 40, 50, 30, 20]
// 擷取滿足條件的元素
print(a.last(where: { $0 > 30 }))   //50
// 擷取滿足條件的元素的索引
print(a.lastIndex(where: { $0 > 25 }))   //4
           

4.5 新增 random() 随機數方法來生成一個随機數, 隻需提供一個随機數範圍即可

// 随機數
let ranInt = Int.random(in: 0..<10)
let ranFloat = Float.random(in: 0..<10)

let a = [10, 20, 30, 40, 50, 30, 20]
// 對數組重新洗牌, 重新随機排序傳回一個數組
let shuffled = a.shuffled()
// 擷取數組中的一個随機元素,空數組傳回nil
let random = a.randomElement() 
           

4.6 新增 removeAll(where:) 方法,高效地執行根據條件删除操作

var names = ["John", "Michael", "Graham", "Andy", "Eric", "Andy"]
names.removeAll { $0.hasPrefix("Andy") }
print(names)
// 輸出:["John", "Michael", "Graham", "Eric"]
           

5. Swift 5.0 新特性

5.1 ABI(Application Binary Interface)穩定:ABI定義了函數如何調用,資料如何在記憶體中呈現,中繼資料在哪裡,以及如何通路等底層互動。之前的Swift版本中ABI還沒穩定,是以每一個APP,都自己包含它Swift版本所對應的Swift Dynamic Library。ABI穩定之後,Swift動态庫将包含在iOS作業系統裡,它将相容每一個Swift版本。

5.2 新增 @dynamicCallable 為Swift添加了一個新屬性,允許使用一個簡單的文法糖像調用函數一樣調用命名類型,需要實作下面兩個方法中的一個:

func dynamicallyCall(withArguments args: [Int]) -> Double
func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Int>) -> Double
           
// 定義方式
@dynamicCallable
struct RandomNumberGenerator {
    func dynamicallyCall(withArguments args: [Int]) -> Double {
        let numberOfZeroes = Double(args.first ?? 0)
        let maximum = pow(10, numberOfZeroes)
        return Double.random(in: 0...maximum)
    }
}
// 調用方式
let random = RandomNumberGenerator()
let num = random(2)
// random(2)等同于random.dynamicallyCall(withArguments: [2])
           

5.3 修改:定義一個帶有(可變參數 => 數組參數)的枚舉

enum X {
    case foo(bar: [Int]) 
} 
func baz() -> X {
    return .foo(bar: [0, 1, 2, 3]) 
} 
           

5.4 新增建立原始字元串的功能,以及建立多行字元串

let quote = "Alice: \"How long is forever?\" White Rabbit: \"Sometimes, just one second.\""
let rain = #"The "rain" in "Spain" falls mainly on the Spaniards."#
let multiline = #"""
    The answer to life,
    and everything is \#(answer).
    """#
           

5.5 Swift 5中無論有多少個嵌套的可選,最後傳回值永遠隻是一個可選值,使用try?

// 類型: let messages: String?
let messages = try? user?.getMessages()
print(messages ?? "")
           

5.6 新增了一個函數 count(where:),可以擷取數組中符合條件的元素的個數

let arr = [1, 28, 3, 40, 5, 6]
let count = arr.count(where: { $0 > 10 })
print(count)  // 2
           

5.7 在 Swift4.x 的版本中有兩個函數 compactMap 和 mapValues

compactMap: 傳回一個操作後得到的新的數組, 類似flatMap

mapValues: 對字典的value值執行操作, 傳回改變value後的新的字典

Swift5.0 新增了一個函數 compactMapValues 傳回一個對value操作後的新字典, 并且自動過濾不符合條件的鍵值對

let guys = [
    "Hudson": "30",
    "Clarke": "40",
    "Robinson": "50",
    "Hartis": "DNF"
]
let comMap = guys.compactMapValues({ Int($0) + 3 })
print(comMap)
// ["Clarke": 43, "Robinson": 53, "Hudson": 33]