Document

Swift编码规范

命名(Naming)

使用驼峰命名规则和描述性的名称来定义类、方法、变量等。类名和模块中的常量的第一个字母应该大写,而方法名和变量应该开始用小写字母。

好的示例(Preferred):

let MaximumWidgetCount = 100

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

不太好的(Not Preferred):

let MAX_WIDGET_COUNT = 100

class app_widgetContainer {  
    var wBut: UIButton  
    let wHeightPct = 0.85
}

对于方法和init函数,需要对所有参数进行命名除非上下文是非常清楚的。包括外部的参数名称,如果它使函数调用更具可读性。

func dateFromString(dateString: NSString) -> NSDate
func convertPointAt(#column: Int, #row: Int) -> CGPoint
func timedAction(#delay: NSTimeInterval, perform action: SKAction) -> SKAction!

// would be called like this:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(delay: 1.0, perform: someOtherAction)

对于方法,按照苹果关于方法第一个参数的标准:

class Guideline {  
    func combineWithString(incoming: String, options: Dictionary?) { 
        ... 
    }  

    func upvoteBy(amount: Int) { 
        ... 
    }
}

当在文章中(教程,书籍,评论)包含函数代码是,需要从调用者的角度考虑所需要的参数名称。如果上下文是明确的,确切的签名并不重要,你可以只使用方法名。

类前缀(Class Prefixes)

Swift会自动为模块中的类型增加命名空间。因此,不需要为避免名字冲突为类型增加前缀。如果不同模块的两个名字有冲突,那么可以通过模块名来解决合格问题。

import MyModulevar myClass = MyModule.MyClass()
你不需要为你的Swift类型增加潜水

You should not add prefixes to your Swift types.

如果你需要编写在Objective-C中使用的Swift类型,你可以各一个适当的前缀(请参考我们的Objective-C的风格指南):

If you need to expose a Swift type for use within Objective-C you can provide a suitable prefix (following our Objective-C style guide) as follows:

@objc (RWTChicken) class Chicken {   
    ...
}
空白(Spacing)

使用缩进2个空格,而不是制表符,以节省空间,并有助于防止换行。请务必在Xcode中设置此偏好。 方法括号和大括号等(if/else/switch/while等)总是在同一行语句打开在新行关闭。

好的示例(Preferred):

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

不太好的(Not Preferred):

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

为了阅读方便应该在方法之间保持一个空行以更好的组织代码。在方法中空行应该分割功能块,但如果一个方法有太多的功能块,那么通常意味着你应该重构到多个方法中。

注释(Comments)

当需要的时候,使用注释来解释特定代码的功能,注释必须保持最新或删除。避免在代码块内的大块注释,该代码应该是自我描述的。例外:这并不适用于那些用来生成文档的注释。

类和结构(Classes and Structures)

下面是一个较好的类定义格式

class Circle: Shape {
  var x: Int, y: Int
  var radius: Double
  var diameter: Double {
    get {
      return radius * 2
    }
    set {
      radius = newValue / 2
    }
  }

  init(x: Int, y: Int, radius: Double) {
    self.x = x
    self.y = y
    self.radius = radius
  }

  convenience init(x: Int, y: Int, diameter: Double) {
    self.init(x: x, y: y, radius: diameter / 2)
  }

  func describe() -> String {
    return "I am a circle at \(centerString()) with an area of \(computeArea())"
  }

  override func computeArea() -> Double {
    return M_PI * radius * radius
  }

  private func centerString() -> String {
    return "(\(x),\(y))"
  }
}

上面的示例提供了较好的编码规范指南:

  • 属性,变量,常量,参数的类型和分号之间保持一个空格,如:x: Int 和 Circle: Shape
  • 如果多个变量和结构拥有相同的目的或上下文,那么在一行里定义他们
  • 缩进getter、setter方法和属性观察器
  • 不需要增加默认修饰比如internal。同样,覆盖的方法时,不要重复添加访问修饰符。
  • 使用self(Use of Self)为了简洁,避免使用self因为Swift并不需要用它来访问对象的属性或调用其方法。

当需要在初始化代码中区分属性名称和参数以及在闭包中明确引用属性时使用self:

class BoardLocation {
  let row: Int, column: Int

  init(row: Int,column: Int) {
    self.row = row
    self.column = column

    let closure = { () -> () in
      println(self.row)
    }
  }
}

定义函数(Function Declarations)

对于较短的函数定义,需要在一行中定义:

func reticulateSplines(spline: [Double]) -> Bool {
  // reticulate code goes here
}

对于有很长签名的函数,需要在适当的位置添加换行并且新行需要有额外的缩进。

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

闭包(Closures)

尽可能使用后关闭语法。在所有情况下,闭包的参数需要有一个描述性的名称:

return SKAction.customActionWithDuration(effect.duration) { node, elapsedTime in 
  // more code goes here
}

对于只有一行表达式的闭包,如果上下文清晰的话可以隐式返回。

attendeeList.sort { a, b in
  a > b
}

类型(Types)

尽可能地使用Swift原生类型。Swift提供了对Objective-C的桥接所以在需要的时候仍然可以使用全部的Objective-C方法:

好的示例(Preferred):

let width = 120.0                                    //Double
let widthString = (width as NSNumber).stringValue    //String

不太好的(Not Preferred):

let width: NSNumber = 120.0                                 //NSNumber
let widthString: NSString = width.stringValue               //NSString

在Sprite Kit代码中,使用CGFloat,如果它使代码更简洁,避免过多的转换。

常量(Constants)

常量通过let关键字定义,而变量使用var关键字定义。任何值如果是一个不变量,那么请使用let关键字恰如其分地定义它。最后你会发现自己喜欢使用let远多于far。

Tip:有一个方法可以帮你符合该项规则,将所有值都定义成常量,然后编译器提示的时候将其改为变量。

可选的(Optionals)

  • 在nil值可能出现的情况下,将变量跟函数返回值的类型通过?定义成Optional。
  • 只有在确定实例变量会在初始化之后才被使用的情况下,通过 ! 将其定义为隐式解包类型(Implicitly Unwrapped Types),
  • 比如说会在viewDidLoad中被创建的子视图。 在访问一个Optional值时,如果该值只被访问一次,或者之后需要连续访问多个Optional值,请使用链式Optional语法:

      myOptional?.anotherOne?.optionalView?.setNeedsDisplay()
    

对于需要将Optional值解开一次,然后进行多个操作的情况,使用Optional绑定更为方便:

    if let view = self.optionalView {
      // do many things with view
    }

初始化结构体(Struct Initializers)

使用Swift原生的结构体初始化方法,而不是使用陈旧的CGGeometry构造方法

好的示例(Preferred):

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

不太好的(Not Preferred):

let bounds = CGRectMake(40, 20, 120, 80)
var centerPoint = CGPointMake(96, 42)

类型推断(Type Inference)

Swift的编译器可以推断出变量跟常量的类型。可以通过类型别名(在冒号后面指出其类型)提供显式类型,不过大多数情况下这都是不必要的。

保持代码紧凑,然后让编译器推断变量跟常量的类型。

好的示例(Preferred):

let message = "Click the button"
var currentBounds = computeViewBounds()
不太好的(Not Preferred):

let message: String = "Click the button"
var currentBounds: CGRect = computeViewBounds()

注意:遵循这条准则意味着描述性强的名称比之前更为重要了。

语法糖(Syntactic Sugar)

使用类型定义个快捷语法而不要使用完整的语法

好的示例(Preferred):

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

不太好的(Not Preferred):

var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>

控制流(Control Flow)

对于for循环,优选for-in风格而不是for-condition-increment风格

好的示例(Preferred):

for _ in 0..<3 {
  println("Hello three times")
}

for person in attendeeList {
  // do something
}
不太好的(Not Preferred):

for var i = 0; i < 3; i++ {
  println("Hello three times")
}

for var i = 0; i < attendeeList.count; i++ {
  let person = attendeeList[i]
  // do something
}

分号(Semicolons)

  • Swift在任何语句后都不需要分号,分号仅在你将多个语句写在一行时有用(用于区分语句)
  • 不要将多个语句写在一行然后用分号区分

这个规则的唯一例外是for语句,它需要分号。然而,在可能的情况下尽量使用可选的 for-in 语句

好的示例(Preferred):

var swift = "not a scripting language"

不太好的(Not Preferred:)

var swift = "not a scripting language";

注意:Swift与javascript非常不一样,javascript认为省略分号是不安全的。

语言(Language)

与Apple API一样使用US English 拼写

Preferred:

var color = "red"
Not Preferred:

var colour = "red"

笑脸(Smiley Face)

笑脸对于raywenderlich.com来说是一个格外重要的风格特征。使用正确的笑脸可以表示出对某个主题的无穷尽的高兴以及兴奋程度。选用了]是因为它在ASCII艺术可以表示得最大的笑脸。而闭圆括号)因为给人一种“呵呵”的感觉而不建议使用。

好的(Preferred):

:]
不咋地的(Not Preferred):

:)