你好,歡迎來到IOS教程網

Swift

編輯:IOS開發基礎

1462846365476282.jpg

投稿文章,作者:南栀傾寒(博客)

最近工作也比較穩定了,公司在做代碼規范和組件化的跳轉。 鑒於使用Objective-C的開發成員比較多, 我們架構師就整理了Objective-C的代碼規范。不過作為Swift開發的老司機,也整理了一套適用與Swift的代碼規范。 以後可以直接拿來用了。

注釋

 // 單行注釋
 /*  多行注釋  */
 /// 標記注釋1
 /** 標記注釋2 */

建議使用VVDocument-Xode插件

文檔注釋

以/* ..../ 標記, 不用再沒一行開頭都加*號,支持markdown書寫,例如:

/**
 ## Feature Support
 This class does some awesome things. It supports:
 - Feature 1
 - Feature 2
 - Feature 3
 ## Examples
 Here is an example use case indented by four spaces because that indicates a
 code block:
     let myAwesomeThing = MyAwesomeClass()
     myAwesomeThing.makeMoney()
 ## Warnings
 There are some things you should be careful of:
 1. Thing one
 2. Thing two
 3. Thing three
 */
class MyAwesomeClass {
    /* ... */
}

方法注釋

用 - parameter注釋來標記參數等

/**
 This does something with a `UIViewController`, perchance.
 - warning: Make sure that `someValue` is `true` before running this function.
 */
func myFunction() {
    /* ... */
}

命名

使用可讀的駝峰命名法去給類 方法 變量 命名。 class struct protocol enum 應使用大寫,變量名使用小寫

private let maximumWidgetCount = 100
class WidgetContainer {
  var widgetButton: UIButton
  let widgetHeightPercentage = 0.85
}

對於全局函數,init方法 ,建議每個參數都使用外部變量,來保證可讀性

func dateFromString(dateString: String) -> NSDate
func convertPointAt(column column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// would be called like this:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)

Protocols 協議命名

建議遵守Apple's API DesignGuidelines使用名詞來描述,如 ing able ible,例如

Collection
WidgerFactory
Equtable
Resizing

Emumerations 枚舉命名規范

使用首字母小寫的駝峰命名法給每個case命名

enum Shape {
  case rectangle
  case square
  case rightTriangle
  case equilateralTriangle
}

Class Prefixes類型前綴

官方建議不使用前綴,因為swift有命名空間的概念

但是由於在項目開發中不可避免使用開源庫,大部分使用pods管理,但是有時候需要針對需要定制功能,直接修改源碼,這時候是直接將源碼放在工程中,而且大部分的項目都是混編項目。可能導致命名沖突,此處還建議用LJ(Lianjia)當作命名前綴

class LJHomeViewController: UIViewController {}

Selector選擇器

建議使用可推測的上下文環境,來創建選擇器,而不是點擊Xcode的Fix it ,這樣會產生一個全名稱 選擇器

let sel = #selector(viewDidLoad)

不推薦

let sel = #selector(ViewController.viewDidLoad)

Generics泛型

泛型命名應該使用大寫的駝峰命名法,,如果給一個泛型起名字其實沒意義,可以使用常見的T,U,V來命名

推薦

struct Stack{ ... }
func writeTo(inout target: Target)
func max(x: T, _ y: T) -> T

不推薦

struct Stack{ ... }//命名無意義
func writeTo(inout t: target)// 首字母未大寫
func max(x: Thing, _ y: Thing) -> Thing//簡稱即可

Code Formatting 代碼格式

留空白

  • 建議使用tabs 而不是使用空格

  • 文件結束時留一行空白

  • 用足夠的空行把代碼分割為合理的邏輯塊,而不是非常緊湊

  • 不要在一行代碼結尾處留空格

  • 更不要在空行(\n)中使用縮進(\t)

聲明類型時,將冒號與標識符連在一起

當聲明一個變量時冒號緊跟變量,空一格再寫類型

class SmallBatchSustainableFairtrade: Coffee { ... }
let timeToCoffee: NSTimeInterval = 2
func makeCoffee(type: CoffeeType) -> Coffee { ... }

Control Flow 控制流

建議使用Swift范的for in 循環而不是 while or c 式for循環

for _ in 0..<3 {
  print("Hello three times")
}
for (index, person) in attendeeList.enumerate() {
  print("\(person) is at position #\(index)")
}
for index in 0.stride(to: items.count, by: 2) {
  print(index)
}
for index in (0...3).reverse() {   //3,2,1,0
  print(index)
}

代碼塊縮進

(if/else/switch/while etc.)或者method function 的大括號留在當前行,並前保留一個空格 ,能省略的不要添加

if user.isHappy {
  // Do something
} else {
  // Do something else
}

不推薦

if (user.isHappy ) 多余空格
{                  換行位置不對
  // Do something
}
else {
  // Do something else
}

Early Return

當你遇到某些操作需要條件判斷去執行,應該使用防御式編程 盡早返回

guard n.isNumber else {
    return
}
guard let number1 = number1, number2 = number2, number3 = number3 else { fatalError("impossible") }
// do something with numbers
// Use n here
//guard 理解為確保的意思,  如 確保n是一個數字
不推薦使用if判斷
if n.isNumber {
    // Use n here
} else {
    return
}
if let number1 = number1 {
  if let number2 = number2 {
    if let number3 = number3 {
      // do something with numbers
    }
    else {
      fatalError("impossible")
    }
  }
  else {
    fatalError("impossible")
  }
}
else {
  fatalError("impossible")
}

Semicolons 分號

不要寫分號,不要寫分號,不要寫分號 Swift不同於JavaScript ,詳情參看:

generally considered unsafe---Do you recommend using semicolons after every statement in JavaScript?

更不建議把多句代碼塊放在一行中

自定義運算符的時候左右盡量各保留一個空格

func <|(lhs: rhs:="" -=""> Int
func <|<(lhs: A, rhs: A) -> A
// 重構後
func <| lhs:="" rhs:="" -=""> Int
func <|< (lhs: A, rhs: A) -> A

代碼分割

使用良好的代碼分割讓你的代碼塊更具有邏輯性

// MARK: -      類似@parma mark -
// MARK:        類似@parma mark

ProtocolConformance 協議保持一致性

一個類型實現一個協議時建議單獨聲明一個擴展,保證邏輯性分離

class MyViewcontroller: UIViewController {
  // class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
  // table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
  // scroll view delegate methods
}

不推薦實現的所有協議寫在一起

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

無用的代碼要刪除

無用的代碼和注釋要刪除 ,避免給閱讀代碼的人造成困惑和疑問

類型定義

盡可能的使用swift自帶類型,在必須的時候才做橋接 ,String-> NSString , Set->NSSet

更多的使用let,而不是var

盡量let foo = something 而非 var  for = somthing

let-有保障 並且它的值的永遠不會改變,對同事也是個 清晰的標記,對於它的用法,之後的代碼可以做個強而有力的推斷。更容易明白代碼的含義。否則的話一旦你用了 var,還要去考慮值會不會改變,這時候你就不得不人肉去檢查。

這樣,無論何時你看到 var,就假設它會變,並找到原因。

常量

不建議直接命名頂級變量,建議定義在結構體或者枚舉內部,用static let 聲明。 可以給這些變量一個合適的命名空間

enum Math {
  static let e  = 2.718281828459045235360287
  static let pi = 3.141592653589793238462643
}
radius * Math.pi * 2 // circumference

Optional可選類型

盡量不要使用強制解包

對於一個可選類型var foo = Type? 不要使用強制解包

foo!.doSomethind()

使用可選綁定,或者  可選鏈操作

if let foo = foo {
    // Use unwrapped `foo` value in here
} else {
    // If appropriate, handle the case where the optional is nil
}
//或者
// Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call
foo?.callSomethingIfFooIsNotNil()

避免使用隱式可選類型

如果 foo 可能為 nil ,盡可能的用 let foo: FooType? 代替 let foo: FooType!(注意:一般情況下,?可以代替!)

Struct Initializers 結構體初始化

使用結構體初始化而不是CGGet。。。之類的創建方法

let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)

Lazy Initialization

對於較大開銷的初始化或者配置較多的初始化建議放在加載屬性裡

lazy var locationManager: CLLocationManager = self.makeLocationManager()
private func makeLocationManager() -> CLLocationManager {
  let manager = CLLocationManager()
  manager.desiredAccuracy = kCLLocationAccuracyBest
  manager.delegate = self
  manager.requestAlwaysAuthorization()
  return manager
}

Classes and Structures 結構體和類

首選struct而非class

在非必需(比如沒有生命周期)的時候使用struct,因為多態可以使用protocl實現 繼承可以使用組合實現

值類型容易辨別,更可以用let去推測不可變的行為

只有在必須時才使用self

忘掉Objective-C到底時使用self.pro 還是_ivar的訪問方式,對於swift內部調用properties或者method省略掉self

private class History {
    var events: [Event]
    func rewrite() {
        events = []
    }
}

只有在使用閉包或者命名沖突時再加上self

extension History {
    init(events: [Event]) {
        self.events = events
    }
    var whenVictorious: () -> () {
        return {
            self.rewrite()
        }
    }
}

只有在使用閉包時self 增強了被捕獲的語義,其它時候是冗余的

對於只讀的屬性或者下標語法,使用隱式的getter方法

建議

var myGreatProperty: Int {
    return 4
}
subscript(index: Int) -> T {
    return objects[index]
}

不建議完整的寫法,比較繁瑣

var myGreatProperty: Int {
    get {
        return 4
    }
}
subscript(index: Int) -> T {
    get {
        return objects[index]
    }
}

請把class默認標記為final

組合通常比繼承更合適,而且不用 繼承意味著考慮的更加健壯

// Turn any generic type into a reference type using this Box class.
final class Box{
  let value: T
  init(_ value: T) {
    self.value = value
  }
}

類型推斷

能讓系統推斷的類型不要顯示指明

struct Composite{
    func compose(other: Composite) -> Composite{
        return Composite(self, other)
    }
}
let num:Int = 4

重構為

struct Composite{
    func compose(other: Composite) -> Composite {
        return Composite(self, other)
    }
}
let num = 4

空的字典和空數組的類型 使用類型標記 加強語義

var names: [String] = []
var lookup: [String: Int] = [:]

函數聲明

函數名要簡短清晰,如果能保持在一行內,大括號也要保持在一行,如果不能換行並用Tab\b縮進

func reticulateSplines(spline: [Double]) -> Bool {
  // reticulate code goes here
}
func reticulateSplines(spline: [Double], adjustmentFactor: Double,
    translateConstant: Int, comment: String) -> Bool {
  // reticulate code goes here
}

閉包表達式

使用尾隨閉包提高可讀性,

UIView.animateWithDuration(1.0) {
  self.myView.alpha = 0
}
UIView.animateWithDuration(1.0,
  animations: {
    self.myView.alpha = 0
  },
  completion: { finished in
    self.myView.removeFromSuperview()
  }
)

常見的閉包語義可以使用其縮略形式

let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.indexOf(90)
let value = numbers
   .map {$0 * 2}
   .filter {$0 > 50}
   .map {$0 + 10}

Syntactic Sugar語法糖

對於有語法糖的建議使用,提升可讀性

var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?

而不是

var deviceModels: Array
var employees: Dictionary
var faxNumber: Optional

內存管理

對於class類型需要注意內存管理

普通的閉包建議使用[weak self] 或者[unowned self] 對於異步的閉包建議使用 [weak self] and  guard let strongSelf = self else { return }搭配使用

weak 避免出現循環引用, strongself 避免在異步回調中 捕獲列表中捕獲的變量被析構

resource.request().onComplete { [weak self] response in
  guard let strongSelf = self else { return }
  let model = strongSelf.updateModel(response)
  strongSelf.updateUI(model)
}

對於頂級類型,函數,變量定義,明確的列出權限控制

對於全局變量 頂級函數,類型,永遠應該有著詳盡的權限控制說明符

public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}

參考自

Github

LinkedIn

Prolificinterative

Raywenderlich

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved