[iOS] Swift Coding Style

Coding Style有時候是主觀的, 這邊主要整理了Apple Sample Code與Clean Code所提供的規則

命名規則

(1.) Apple以Camel Case (駝峰法)方法命名, 除了第1個單字, 每個單字的開頭大寫.

ex: 宣告1個Button

  var theFirstButton = UIButton()    (O)
  var Thefirstbutton = UIButton()    (X)  

(2.) 名字要能夠念出來, 不要用縮寫.

ex: 宣告1個Button

  var theFirstButton = UIButton()    (O)
  var theFirstBtn = UIButton()       (X)  

(3.) 宣告array時, 用s結尾

ex: 宣告1個button array

  var buttons: [UIButton] = []        (O)
  var buttonList: [UIButton] = []     (X)  

(4.) IBOutlet 元件的命名, 其變數結尾與元件型別有關

ex: 宣告1個IBOutlet button

@IBOutlet weak var theFirstButton: UIButton!        (O)
@IBOutlet weak var theFirstTouch: UIButton!         (X)  

(5.) IBAction function的命名, 其function結尾與事件有關

ex: 宣告1個IBOutlet button 的 touchUpInside function

@IBAction func theFirstButtonTouchUpInside(_ sender: UIButton) {       (O)
}   

(6.) Singleton或共用的實體, 取名為shared

ex: 宣告一個Singleton Class

class SingletonClass {       
   static let shared = SingletonClass()
}

(7.) Class與資料夾名稱以Camel Case (駝峰法)方法命名, 但第1個字也是大寫

ex: 宣告一個 Class

class MyClass {       
}

(8.) Function的命名盡量以動詞開頭, 參數越少越好, 1個Function只做單一的1件事情,

內容越精簡且越有可讀性越好

ex:

func updateUI() {  
    self.updateTitleLabel()  
    self.updateButtonColor()   
}

func updateTitleLabel() { 
  //只更新TitleLabel  
}

func updateButtonColor() {   
  //只更新ButtonColor     
}

(9.) 較短的命名若能解釋清楚, 勝過較長的命名

較短的命名若不能解釋清楚, 較長的命名更好

(10.) 統一的命名, 比如說跟更新UI有關的function都用update開頭, 方便搜尋

ex:

func updateUI() {       
}

func updateTitleLabel() {       
}

func updateButtonColor() {       
}

(11.) Delegates命名, 第一個參數通常是delegate source

ex:

func myViewDidSelect(_ myView: MyView, name: String)                 (O)
func myViewShouldReload(_ myView: MyView) -> Bool                    (O)


func myView(name: String)                                            (X)
func myViewShouldReload() -> Bool                                    (X)

縮排

(1.) 括號與換行

Swift推的:

if (isHappy) {
  // Do something
} else {
  // Do something else
}

比較少人用的:

(微軟推的, 仔細觀察apple 的 sample code, 偶而也會有這種style出現)

if (isHappy)
{
  // Do something
}
else 
{
  // Do something else
}

(2.) 冒號, 逗號後留一個空格

let names: [String: String] = ["developer": "frank", "team": "F&Z"]

(3.) -> 前後留一個空格

func myViewShouldReload() -> Bool  

(4.) { 前留一個空格

if (isHappy) {
  // Do something
}

(5.)空白行

空白行是必要的, 代表一個邏輯的轉折

func myViewShouldReload() -> Bool {
   var number = 0
   var title = "myName"

   self.doSomething()
   self.doAnotherThing()
}

註解

(1.) 最好的註解就是不需要使用註解, 由命名上就能了解程式的意義, 有時讀註解比讀code更花時間, 也必須花額外時間去維護註解.

(2.) TODO

if (isHappy) {
  // TODO: Do something
}

(3.) 警告特殊情形

if (isHappy) {
  // something will happen...
}

Protocol 實作

Preferred:

class ViewController: UIViewController {
}

// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
}

// MARK: - UIScrollViewDelegate
extension ViewController: UIScrollViewDelegate {
}

Not Preferred:

class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
  // all methods
}

宣告

(1.) 宣告空白Array & Dictionary

Preferred:

var titles: [String] = []
var songs: [String: Int] = [:]

Not Preferred:

var titles = [String]()
var songs = [String: Int]()

(2.) 使用structure儲存相關的變數

struct StoryboardID {
    static let viewController = "viewController"
    static let noteViewController = "noteViewController"
    static let newViewController = "newViewController"
}

(3.) 使用enum使參數變得有意義

enum payType :Int {
    case cash, card, other
}

MVC (Model, View, Controller)

MVC為iOS App 開發最常用的架構, 但Apple 提到除了 view controller, 還可以另外建立 model controller 和 helper controller, 讓程式的分工更為清楚.

(1.) Model Controller

負責實現 model 的相關功能. 比方你在做一個資料庫 App, 要處理 data的新增, 修改, 刪除, 查詢等動作, 可以另外定義一個dataController 實現來相關功能, 讓viewController更為精簡

(2.) Helper Controller

負責特定的功能, 例如可以建立一個 NetworkController, 專門處理 App與後台溝通的部分

Guard

(1.) 利用guard 判斷tableview的cell

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        guard cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as? MyCell else {
            fatalError("dequeueReusableCell failed")
        }
        
        cell.initWithData()

        return cell
}

(2.) 利用guard 一次判斷

func saveData(data: MyData?, name:String?) {
    guard data != nil,
        name != nil,
        name.count > 0 else {
            return
    }
    
    //do something here
}

nil-coalescing operator

利用 ??語法設定變數為nil時的預設值

let userName = userNameTextField.text ?? "unknown"          

Last updated