这份风格指南不同于你看到的那些,因为(本指南的)焦点集中在打印的可读性和web上。我们创建这份风格指南来让我们书里的代码、教程、starterkits 友好以及一致,即使我们的书面向许多不同的读者。
我们首要的目标是简要性、可读性和简单。
命名
使用驼峰的描述性命名来为类、方法、变量等命名。类名必须大写,方法名和变量应该以小写字母开头
推荐:
private letmaximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}
不推荐:
let MAX_WIDGET_COUNT = 100
class app_widgetContainer {
var wBut: UIButton
let wHeightPct = 0.85
}
对于函数和初始化方法,推荐为所有参数命名,如果参数的内容非常明确则不用。如果外部参数的全命名能让函数更可读,那么也推荐命名外部参数。
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)
对于方法而言,遵照苹果官方的约定标准:根据第一个参数来命名方法
class Counter {
func combineWith(otherCounter: Counter, options: Dictionary?) { ...
}
func incrementBy(amount: Int) { ...}
}
枚举类型
使用大写的驼峰命名为枚举类型命名
enum Shape {
case Rectangle
case Square
case Triangle
case Circle
}
散文化命名(prose)
当散文(教程、书、注释)中提到的函数包含了调用者视角的必须参数名或没有命名参数下划线_。(意思就是函数命名要写成散文一样可读,像下面这个,还举了官方的例子)
Call convertPointAt(column:row:) from
your own init implementation.
If you
call dateFromString(_:) make sure that you provide a string
with the format "yyyy-MM-dd".
If you
call timedAction(afterDelay:perform:) from viewDidLoad() remember
to provide an adjusted delay value and an action to perform.
You shouldn't call the data
source method tableView(_:cellForRowAtIndexPath:) directly.
如果你怀疑的话,看看Xcode在弹出栏列出的方法名,我们这里的风格和Xcode的是匹配的。
类前缀
swift的类型是自动被拥有他们的模块创建命名空间的,你不用加类前缀。如果不同模块的两个命名冲突了,你可以通过用模块名做类名的前缀来解决
import SomeModule
let myClass =MyModule.UsefulClass()
空格
缩进使用2个空格而不是tabs,如下图
方法的花括号或其他花括号(if/else/switch/while etc)总是写在语句的同一行,而新开一行来结束。
提示:你可以通过选中一些代码然后control - l来重缩进。一些Xcode的模板代码有4个空格的tabs,你可以用这个方法来修改。
推荐:
if user.isHappy {
// Do something
} else {
// Do something else
}
不推荐:
if user.isHappy
{
// Do something
}
else {
// Do something else
}
方法之间要留有明显的一个空行,辅助视觉上的清晰感和组织性。
方法内的空白应该按功能分开,但是有太多空白块的haunted说明你需要重构该方法为多个方法。
注释
如果需要的话,使用注释来解释为什么一个特别的代码块要执行。注释必须保持更新或者删除
避免代码中的块注释,代码应该尽可能自注释。除非注释不被应用于那些产生文档的。
类和结构体
选择哪一个
记住,结构是值语义。使用结构是面向无实体的。一个包含[a,b,c]的数组和另一个含有[a,b,c]的数组是一样的,而且他们完全可以互换。不管你使用第一或第二个数据都没关系,因为他们代表同一份数据,这就是为什么数组是结构。
类是引用语义。使用类是面向那些有实体或具体声明周期的。你可以给一个person建模成为一个类,两个person对象是不一样的。两个人拥有相同的名字和生日,并不意味着这就是完全相同的两个人。但是person的生日是一个结构,因为1950年的三月和另一个人的1950年三月是相同的。日期本身不含有实体。
有时候,使用结构体但需要遵从AnyObject,或者被构造成类(NSDate,NSSet),请尽力遵守这些原则。
例子定义
下面是一个关于好的样式的类定义
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
}
convenienceinit(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 funccomputeArea() ->Double
{
return M_PI *radius *
radius
}
private funccenterString() ->String
{
return "(\(x),\(y))"
}
}
上面这个例子阐述了下列的样式指南:
确定属性、变量、常量、参数声明和其他语句的类型,在冒号后加空格而不是在前面,比如var x: Int, y: Int
如果目的或内容相同,可在一个单行上定义多个变量和结构体
getter和setter,属性observers缩进
不要加上修饰符如internal,当他们是默认的时候。相似的,当重写方法时不要重复访问符号
使用self
为了更精准,避免使用self,因为swift不需要拥有self来访问一个对象的属性或者调用他的方法
使用self,当需要在初始化器中区分属性名和参数名的时候,还有在闭包表达式中引用属性的时候。
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row =row
self.column =column
let closure ={
println(self.row)
}
}
}
协议
当像一个类添加遵从协议时,将协议方法添加到类的extension是比较好的做法。这样能让相关联的方法成组,也能简化类的结构,当向一个类的协议中添加方法时。
不要忘记使用//MARK: -注释,这种注释能让代码有好的组织性。
推荐
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
}
Not Preferred:
class MyViewcontroller: UIViewController, UITableViewDataSource,
UIScrollViewDelegate {
// all methods
}