raywenderlich的Swift编程风格指南

这是一份raywenderlich的Swift编程风格指南,中文版由@mrahmiao翻译,你可以前往Github访问这个项目。

因为该指南关注于网页上以及打印版的可读性,所以它可能与你阅读过的指南有所不同。为了保证那些在我们书中、教程里以及初学者工程里的代码美观并且一致,我们写下了这份风格指南,尽管书由许多不同作者共同创作而成。

该指南的首要目标是让代码紧凑,可读性高且简洁。

正在用Objective-C写程序?也看看我们的Objective-C风格指南吧。

语言

使用美式英语拼写以确保和苹果公司的API一致。

优选:
<pre><code>var color = "red"</pre></code>
不建议使用:
<pre><code>var colour = "red"</pre></code>

间隔

使用2个空格而不是Tab进行缩进,可以减少换行。确保在Xcode的配置项中使用此设置。

方法的花括号以及其它花括号(if/else/switch/while等等)总是跟语句在同一行开始,新起一行结束。
优选:
<pre><code>if user.isHappy {
//Do something
} else {
//Do something else
}</pre></code>
不建议使用:
<pre><code>
if user.isHappy
{
//Do something
}
else {
//Do something else
}</pre></code>
方法之间应该总是用一个空行进行分隔以提高视觉以及结构上的清晰度。方法中的空白用来分开功能块,但是如果一个方法中存在太多功能块时,通常意味着你需要将它重构为多个方法。

注释

在需要的时候使用注释说明一块代码为什么这么做。注释必须时刻跟进代码,不然不如不要。

代码应该尽可能的自文档化,避免在代码中使用成块的注释。例外:该规则不适用与用于生成文档的块注释。

命名

使用驼峰法为类、方法、变量等取一个描述性强的名字。模块范围的类名和常量名以大写字母开头,而方法名和变量名应以小写字母开头。
优选:
<pre><code>let MaximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}</pre></code>
不建议使用:
<pre><code>let MAX_WIDGET_COUNT = 100
class app_widgetContainer {
var wBut: UIButton
let wHeightPct = 0.85
}</pre></code>
对于函数以及初始化方法,除非上下文含义非常清楚,推荐对所有的参数都加以命名。如果外部参数名称可以使得函数调用更易读,请加上它。
<pre><code>func dateFromString(dateString: NSString) -> NSDate
func convertPointAt(#column: Int, #row: Int) -> CGPoint
func timedAction(#delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// 会被这样调用
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(delay: 1.0, perform: someOtherAction)</pre></code>
对于方法,遵循苹果公司的命名规范,在方法名中提及第一个参数:
<pre><code>class Guideline {
func combineWithString(incoming: String, options: Dictionary?) { ... }
func upvoteBy(amount: Int) { ... }
}</pre></code>
在所有提及到函数的内容中(包括教程,书以及评论),请从调用者的视角进行考虑,将所有的必要参数名都包含进来:
<pre><code>dateFromString()函数真是太棒了。
在你的init()方法中调用convertPointAt(column:, row:)。
timedAction(delay:, perform:)的返回值可能为nil。
Guideline对象只有两个方法:combineWithString(options:)和upvoteBy()。</pre></code>
你不应该直接调用数据源方法tableView(cellForRowAtIndexPath:)。
类前缀

Swift中的类型会被自动加入包含它们的模块的命名空间。所以减少命名冲突的前缀已经不必要了。如果同模块的两个名称冲突了,可以在名称前加上模块名消除歧义:
<pre><code>import MyModule
var myClass = MyModule.MyClass()
</pre></code>
不应该给自己创建的Swift类型加前缀。

如果需要把Swift类型暴露给Objective-C使用,你可以添加一个合适的前缀(前缀的命名请参考Objective-C风格指南):
<pre><code>@objc (RWTChicken) class Chicken {
...
}</pre></code>
分号

Swift不要求每条语句后加分号。只有在你想把多条语句写到一行时才需要加上分号。

请不要在一行中写上用分号隔开的多条语句。

这条规则的唯一例外就是for-conditional-increment结构,该结构中分号是必需的。不过请尽量用for-in结构代替它们。

优选:

1
<pre><code>var swift = "not a scripting language"</pre></code>
不建议使用:

1
<pre><code>var swift = "not a scripting language";</pre></code>
请注意:Swift与JavaScript不同, 在后者中省略分号通常是不安全的。

类与结构体

下面是一个风格良好的类定义代码例子,请参考:
<pre><code>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 ((x),(y)) with an area of (computeArea())"
}

func computeArea() -> Double {
return M_PI * radius * radius
}
}</pre></code>
上面的例子阐述了如下的风格准则:

· 给属性、变量、常量、参数及其它语句指定类型时,在冒号的后面加上空格而不是前面,比如:x: Int跟Circle: Shape。

· 对getter跟setter定义以及属性观察器进行缩进。

· 如果多个变量、结构有着同样的目的或者上下文,在同一行上进行定义。

Self的使用

在Swift中访问对象属性或调用方法时不需要使用self,请避免使用它。

使用self的唯一理由是在初始化一个类或结构体时区分属性名和参数名:
<pre><code>class BoardLocation {
let row: Int, column: Int

init(row: Int,column: Int) {
self.row = row
self.column = column
}
}</pre></code>
函数声明

保持函数声明短小精悍,保持在一行内,花括号在同一行内开始:
<pre><code>func reticulateSplines(spline: [Double]) -> Bool {
// reticulate code goes here
}</pre></code>
对于有着长签名的函数,请在适当的位置进行断行且对后续行缩进一级:
<pre><code>func reticulateSplines(spline: [Double], adjustmentFactor: Double,
translateConstant: Int, comment: String) -> Bool {
// reticulate code goes here
}</pre></code>

闭包

尽可能地使用尾闭包语法。在所有的情况下给闭包参数一个描述性强的名称:
<pre><code>return SKAction.customActionWithDuration(effect.duration) { node, elapsedTime in
// more code goes here
}</pre></code>
对于上下文清晰的单表达式闭包,使用隐式的返回值:
<pre><code>attendeeList.sort { a, b in
a > b
}</pre></code>

类型

如果可能,使用Swift的原生类型。Swift提供了对Objective-C的桥接,如果需要,仍然可以使用全部的Objective-C方法:

优选:

1
2
<pre><code>let width = 120.0 //Double
let widthString = width.bridgeToObjectiveC().stringValue </pre></code>//String
不建议使用:

1
2
<pre><code>let width: NSNumber = 120.0 //NSNumber
let widthString: NSString = width.stringValue </pre></code> //NSString
在Sprite Kit的代码中,如果CGFloat可以避免过多的转换从而使得代码简洁,那么请使用它。

常量

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

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

Optional

在nil值可能出现的情况下,将变量跟函数返回值的类型通过?定义成Optional。

只有在确定实例变量会在初始化之后才被使用的情况下,通过!将其定义为隐式解包类型(Implicitly Unwrapped Types),比如说会在viewDidLoad中被创建的子视图。

在访问一个Optional值时,如果该值只被访问一次,或者之后需要连续访问多个Optional值,请使用链式Optional语法:

1
myOptional?.anotherOne?.optionalView?.setNeedsDisplay()
对于需要将Optional值解开一次,然后进行多个操作的情况,使用Optional绑定更为方便:
<pre><code>if let view = self.optionalView {
// do many things with view
}</pre></code>

类型推导

Swift的编译器可以推导出变量和常量的类型。可以显式地提供类型别名(冒号后面声明的类型),不过大多数情况下这都是不必要的。

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

优选:

1
2
<pre><code>let message = "Click the button"
var currentBounds = computeViewBounds()</pre></code>
不建议使用:

1
2
<pre><code>let message: String = "Click the button"
var currentBounds: CGRect = computeViewBounds()</pre></code>
注意:遵循这条准则意味着使用描述性强的名称比之前更为重要了。

语法糖

Prefer the shortcut versions of type declarations over the full generics syntax.

使用简写的类型声明,而不是它的全泛型版本。

优选:
<pre><code>var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?</pre></code>
不建议使用:

<pre><code>var deviceModels: Array var employees: Dictionary var faxNumber: Optional</pre></code>

控制流

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

优选:
<pre><code>for _ in 0..<3 {
println("Hello three times")
}

for person in attendeeList {
// do something
}</pre></code>
不建议使用:
<pre><code>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
}</pre></code>

笑脸

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

优选:
<pre><code>
:]</pre></code>
不建议使用:
<pre><code>:)</pre></code>
以上。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容