Swift 代码规范

版本记录

版本号 时间
V1.0 2018.12.4

前言

Swift是编写软件的绝佳方式,无论是用于手机,台式机,服务器还是其他任何运行代码的软件。它是一种安全,快速,交互式的编程语言,它将现代语言思维的最佳结合与来自更广泛的Apple工程文化的智慧和来自开源社区的各种贡献相结合。编译器针​​对性能进行了优化,语言针对开发进行了优化,而不会对其进行任何影响。

Swift对新程序员很友好。它是一种工业级编程语言,与脚本语言一样富有表现力和乐趣。在playground上编写Swift代码可以让您试验代码并立即查看结果,而无需构建和运行应用程序的开销。

正文

正确性

力争让代码没有编辑警告(warning)。这个规则下衍生出了许多决定,如:使用#selector方式,而不是直接使用字符串。
注意:由于iOS系统版本升级,同时App支持版本的问题,合理选择正确的未失效方法,可消除部分编译警告。

命名

描述性和一致性的命名会让代码更加的易读、易懂。命名请遵循一下规则:

  • 追求调用方的清晰性
  • 优先使用更清晰的命名,而不是更简洁的命名
  • 使用驼峰样式
  • 类型、协议名首字符大写,其他的都首字母小写
  • 包含所有需要的单词,省略不必要的
  • 使用基于角色的命名,而不是基于类型的
  • 工厂方法使用make开头
  • 对方法的命名
  • 不要使用生僻的单词
  • 通常不要用缩写
  • 选用好的参数名来起到描述的作用
类前缀

Swift中的类型自动使⽤了其所在的模块作为命名空间,所以不必给类型加
前缀。如果来⾃不同模块的类型名字冲突,可以显示的使⽤模块名作为调⽤前缀来避免冲突。

建议

import SomeModule
import OtherModule
let someUsefulClass = SomeModule.UsefulClass()
let otherUsefulClass = OtherModule.UsefulClass()
代理

当定义一个代理⽅法时,第一个匿名参数应该是代理的源对象。( UIKit 中有许多这样的的例子)

建议

func numberOfSections(in tableView: UITableView) -> Int
使⽤可类型推导的上下⽂文

利用好编译器器的类型推断特性,来写出简短、清晰的代码。

建议

self.collectionView.backgroundColor = .white
泛型

泛型参数应当使⽤具有描述性的驼峰样式来命名。当泛型参数不具有
明确的关系或⻆⾊时,可使⽤⼀个⼤写的字母表示即可。如: TUV

使⽤的语⾔

应使⽤用美式英语的拼写⽅方式以匹配Apple的API,应尽量保持命名的可读性,不应该⽤多含义且有相反或者混淆意思的单词。

建议

let color = "white"

不建议

let colour = "white"

代码组织

尽可能的使⽤扩展(extensions)来解耦你的代码,将代码划分到不同的扩展模块中,每个扩展尽量使用// MARK: -开头,用以来更好的区分扩展。

协议的遵守

具体来讲,当让一个Model遵守某个协议时,推荐添加一个独立的Model扩展(extensions)来遵守该协议。这样使得相关的协议⽅法能组织在一起。

对于 UIKit 的视图控制器(view controllers),可以考虑将⽣生命周期(LifeCycle)相关、⾃定义访问器( custom accessors )、 IBAction 独⽴不同的到类扩展中。

建议

// MARK: - UITableViewDelegate
extension XXViewController: UITableViewDataSource, UITableViewDelegate
⽆用的代码

⽆用的代码包括Xcode产⽣生的模板代码、占位的注释等、⽅法的默认实现仅仅是调用 super 等,这些都应当移除掉。

建议

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.dataList.count
}

不建议

// 该方法什么都没干,存在反而会增加小伙伴的阅读量
override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
}
减小引入

保存最小的引入(imports)。例如, 当只使用Foundation时,不要引⼊入UIKit

空格
  • 代码折行使用4个空格
  • 方法的大括号和其他大括号(if/else/switch/while),其左括号必须要和语句在同一个行,并且右括号要换行;
    建议
if XXX == 1 {
    // do something
} else {
    // do something else
}
  • 变量类型和冒号(:)之间保留一个空格;
    建议
let cellHeight: CGFloat = 73.5
  • 返回值标记(->)两侧各保留一个空格;
    建议
func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect
  • 各个方法之间必须有一个空格,这使得代码视觉上更清晰;
  • 方法的实现中,应当适当的添加空行来划分功能。过多的空行意味着应该拆分这些功能到不同的方法中,通过这样来避免一个巨大的方法;
  • 通常冒号(:)的左边应当没有空格,而在右边有一个空格。当然这个是有例外的,如:三目运算符、空字段、无参数方法等;

建议

var delegate: UICollectionViewDelegate?
注释
  • 给方法或者属性添加注释,可以使用option + command + /来让Xcode自动生成,也可以使用MARK: -等;
    option + command + /效果如下
/// <#Description#>
    ///
    /// - Parameters:
    ///   - pageNo: <#pageNo description#>
    ///   - lon: <#lon description#>
    ///   - lat: <#lat description#>
    ///   - state: <#state description#>
    ///   - responseComplete: <#responseComplete description#>
    func requstNetData(_ pageNo: Int,
                       _ lon: Double,
                       _ lat: Double,
                       _ state: Int,
                       _ responseComplete: HttpComplete) {
        
    }
  • 给关键逻辑添加一些局部注释,单行注释请用//;
  • 注释要保持最新状态;

类与结构体

结构体(struct)是值类型,当事物不具有唯一性时,使用结构体。
类是引用类型,当事物具有唯一性或者有明确的生命周期时,使用类。
以下是一个类的定义

class Circle: Shape {
    var x: Int
    var 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)
    }
    override func area() -> Double {
        return Double.pi * radius * radius
    }
}
extension Circle: CustomStringConvertible {
    var description: String {
        return "center = \(_centerString) area = \(area())"
    }
    private var _centerString: String {
        return "(\(x),\(y))"
    }
 }
使用self

在Swift中,可以通过利用好编译器的类型推断特性省略self来访问一个独享的属性或者方法。但是为了消除使用的歧义,建议使用self来访问。

计算属性

为了简洁性,如果⼀个计算属性是只读(read-only)的,那么应省略 get { ... } 语句。get { ... }语句只在计算属性是读写( read-write )时,才要求使⽤。

建议

var area: Double {
    return width * height
}
使用final标记

出于某些原因,你可能不希望一个类被继承,这时你可以将其标记为final来表示它不不能被继承。
例如:一个单例,可能就不希望被继承。

函数声明

  • 将简短的函数声明保留在一行中,包括左括号;

建议

func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
  • 无返回值的函数可以省略(-> Void)返回值;

建议

func register(_ nib: UINib?, forCellWithReuseIdentifier identifier: String)
  • 参数较多的函数可以像Objective-C中一样进行折行处理;

建议

func foo(arg1: Int,
         arg2: Double,
         arg3: String,
         arg4: [Bool],
         arg5: () -> Void) {
    /* code goes here */
}
闭包表达式

当参数列表末尾只有一个闭包参数时,才应该使用尾随闭包语法。

对于使⽤闭包的链式调⽤,应当让代码更清晰、更易读。可以借助空格(spacing)、换⾏(line breaks)和匿名参数(anonymous arguments)等⽅法来让代码更清晰、更易读,但这都依赖于你的选择。

类型

应尽量使用Swift的原生类型,当然Swift提供了对Objective-C类型的桥接方法,你可以使用Objective-C的所有方法。

建议

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

常量使用关键字let定义,变量使用关键字var定义。除非值可变,否则都应该用关键字let定义。
在一个类型的内容,通过关键字static let来定义静态常量,这样可以更好的组织这些静态变量。

建议

enum Math {
    static let e = 2.718281828459045235360287
    static let pi = 3.14159265358979323846264
}

类内部的静态方法和属性,有点类似于全局方法和属性。但应尽量避免使用全局方法和属性。有一些例外情况,比如当使用runtimeobjc_getAssociatedObjec()函数时,需要定义一个全局的key来作为参数。

可选类型

当使用?来定义可选类型时,表明它可以接受为nil的值;
当使用!来定义可选类型时,表明它可以接受为nil的值,但必须保证在使用它时,值不为nil
使用可选绑定来一次性解包单个或多个可选类型值

类型推导

对于局部变量,尽量使用类型推导来让代码更紧凑。而对于成员变量来说,应尽量不要使用类型推导来让类的定义更清晰。

语法糖

利用语法糖,使用更简短的声明方式

内存管理

可以通过使用weakunowned来避免循环引用,但也可以直接使用值类型(struct,enum)来避免循环引用。

可以通过guard let的形式来产生strongSelf

建议

guard let sSelf = self else { return }

访问控制

一般来说,被标记为privatefileprivate的属性或方法都应以下划线(_)开头。例外情况是,当标记被修饰为private(set)fileprivate(set)时,不需要下划线(_)开头,因为他们都是可访问的属性,只是他们都是只读属性而已。

建议

private var _isEnabled: Bool
fileprivate var _isClosed: Bool
private func _foo() {
    // code goes here
}
fileprivate func _bar() {
    // code goes here
}
private(set) var isEnabled: Bool
fileprivate(set) var isClosed: Bool

一般将访问控制标记放在声明的最前面,但例外情况中,当有属性标记@IBAction@IBOutlet@discardableResult@objc时,需要将属性标记放在最前面。

建议

@IBOutlet private var _titleLab: UILabel!

控制流

优先使用for-in的方式而不是while

建议

for (index, person) in attendeeList.enumerated() {
    print("\(person) is at position #\(index)")
}

使用Guard语句

通过使用guard来避免使用if时代码块的深度嵌套问题

建议

 
func check(phone: String?, name: String?, age: Int) -> Bool { 
      // 把对phone、name、age的判断放到⼀一个guard⾥里里,更更简洁
      guard
            let ph = phone, ph.count > 0,
            let nm = name, nm.count > 0,
            age > 0 else {
            return false
            }
            return true 
}

分号

在Swift中不要求必须加分号,一般情况下你不需要使用分号。只有当你希望将多行代码写在一行时,才需要加分号来断句。

圆括号

一般情况下,在类型if条件、for循环等控制语句中不需要加圆空号。只有当你在进行数学运算时,希望代码可读性更高时才需要适当的添加圆括号。
建议

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

推荐阅读更多精彩内容

  • 1. 代码格式 1.1 使用四个空格进行缩进。 1.2 每行最多160个字符,这样可以避免一行过长。 (Xcode...
    余一波_Bobby阅读 5,891评论 1 3
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,724评论 2 9
  • 1.编码格式 1.1 使用四个空格进行缩进(在 Xcode > Preferences > Text Editin...
    Chevee阅读 578评论 0 1
  • 一. 宗旨 尊重苹果原生的命名和书写规范 能清晰表达含义 简洁而不省略 减少不必要的注释 二. 编码规范 1. 运...
    Mccc_阅读 2,191评论 2 12
  • 团队的Swift代码规范,参考Swift Style Guide和Swift 4.0 编码规范,并根据团队实际需要...
    猿类素敌阅读 718评论 0 2