阿凡达

未来可期

287篇博客

【Swift编码规范】(上篇)

阿凡达2018-08-21 11:14

网易漫画在Swift编码上积累了不少经验,新业务开发基本已过渡到Swift,以下为网易杭研文学漫画部制定的Swift编码规范,包括格式规范、命名规范、语法规范,Objective-C兼容四个部分。基于Swift release 3.0.2版本。由于目前Swift还在快速迭代中,此文档后续也会保持同步更新。

1. 格式规范

1.1 使用4个空格进行缩进


1.2 二元运算符(+, ==, 或->)的前后都需要添加空格

推荐

let testValue = 1 + 2

if testValue == 1 {
    /* ... */
}

func testFunction(with testValue: TestClass) -> returnValue {
    /* ... */
}


1.3 一般情况下,在逗号后面加一个空格

推荐

let testArray = [1, 2, 3, 4, 5]

不推荐

let testArray = [1,2,3,4,5]


1.4 每个文件结尾留一行空行


1.5 代码结尾不要使用分号;

推荐

print("Hello World")

不推荐

print("Hello World");


1.6 左大括号不要另起一行

推荐

// 1. Class Define
class TestClass {
    /* ... */
}

// 2. if
if testValue == 1 {
    /* ... */
}

// 3. if else
if testValue == 1 {
    /* ... */
} else {
    /* ... */
}

// 4. while
while isTrue {
    /* ... */
}

// 5. guard
guard let testValue = testValue else  {
    /* ... */
}

不推荐

// 1. Class Define
class TestClass 
{
    /* ... */
}

// 2. if
if testValue == 1
{
    /* ... */
}

// 3. if else
if testValue == 1
{
    /* ... */
}
else
{
    /* ... */
}

// 4. while
while isTrue 
{
    /* ... */
}

// 5. guard
guard let testValue = testValue else 
{
    /* ... */
}


1.7 判断语句不用括号

推荐

if testValue == 1 {
    /* ... */
}

if testValue == 1 && testString == "test" {
    /* ... */
}

不推荐

if (testValue == 1) {
    /* ... */
}

if ((testValue == 1) && (testString == "test")) {
    /* ... */
}


1.8 不建议使用self. ,除非方法参数与属性同名

使用self.情况

func setText(text: String) {
    self.text = test
}


1.9 枚举类型的访问使用更简洁的点语法

推荐

enum CompassPoint {
    case north
    case south
    case east
    case west
}
let directionToHead = .west

不推荐

let directionToHead = CompassPoint.west


1.10 添加有必要的注释,尽可能使用Xcode注释快捷键(⌘⌥/)

推荐

/// <#Description#>
///
/// - Parameter testString: <#testString description#>
/// - Returns: <#return value description#>
func testFunction(testString: String?) -> String? {
    /* ... */
}

不推荐

// Comment
func testFunction(testString: String?) -> String? {
    /* ... */
}


1.11 注释符//后加空格,如果//跟在代码后面,前面也加一个空格

推荐

// 注释
let aString = "xxx" // 注释


1.12 使用// MARK: -,按功能和协议/代理分组

/// MARK顺序没有强制要求,但System API & Public API一般分别放在第一块和第二块。

// MARK: - Public

// MARK: - Request

// MARK: - Action

// MARK: - Private

// MARK: - xxxDelegate


1.13 对外接口不兼容时,使用@available(iOS x.0, *)标明接口适配起始系统版本号

推荐

@available(iOS x.0, *)
class myClass {

}

@available(iOS x.0, *)
func myFunction() {

}


2. 命名规范


2.1 建议不要使用前缀

推荐

HomeViewController
Bundle

不推荐

NEHomeViewController
NSBundle


2.2 不要缩写、简写、单个字母来命名

推荐

let viewFrame = view.frame

不推荐

let r = view.frame


2.3 常量命名:以小写字母k 开头


2.4 变量命名

2.4.1 使用小驼峰,首字母小写
2.4.2 变量命名应该能推断出该变量类型,如果不能推断,则需要以变量类型结尾

推荐

class TestClass: class {
    // UIKit的子类,后缀最好加上类型信息
    let coverImageView: UIImageView
    @IBOutlet weak var usernameTextField: UITextField!

    // 作为属性名的firstName,明显是字符串类型,所以不用在命名里不用包含String
    let firstName: String

    // UIViewContrller以ViewController结尾
    let fromViewController: UIViewController
}

不推荐

class TestClass: class {
    // image不是UIImageView类型
    let coverImage: UIImageView
    // or cover不能表明其是UIImageView类型
    var cover: UIImageView

    // String后缀多余
    let firstNameString: String

    // UIViewContrller不要缩写
    let fromVC: UIViewController
}


2.5 类型命名:使用大驼峰表示法,首字母大写


2.6 方法命名:使用参数标签让方法语义更清楚, 参数标签和参数需要表达正确的语义(Public接口及基础组件必须遵循)

参数标签规则(from Swift API Design Guidelines)

2.6.1 省略所有的冗余的参数标签

推荐

func min(_ number1: int, _ number2: int) {
    /* ... */
}

min(1, 2)
2.6.2 进行安全值类型转换的构造方法可以省略参数标签,非安全类型转换则需要添加参数标签以表示类型转换方法

推荐

extension UInt32 {
  /// 安全值类型转换,16位转32位,可省略参数标签
  init(_ value: Int16)

  /// 非安全类型转换,64位转32位,不可省略参数标签
  /// 截断显示
  init(truncating source: UInt64)

  /// 非安全类型转换,64位转32位,不可省略参数标签
  /// 显示最接近的近似值
  init(saturating valueToApproximate: UInt64)
}
2.6.3 当第一个参数构成整个语句的介词时(如,at, by, for, in, to, with 等),为第一个参数添加介词参数标签

推荐

// 添加介词标签havingLength
func removeBoxes(havingLength length: int) {
    /* ... */
}

x.removeBoxes(havingLength: 12)

例外情况是,当后面所有参数构成独立短语时,则介词提前。

推荐

// 介词To提前
a.moveTo(x: b, y: c)

// 介词From提前
a.fadeFrom(red: b, green: c, blue: d)

不推荐

a.move(toX: b, y: c)

a.fade(fromRed: b, green: c, blue: d)
2.6.4 当第一个参数构成整个语句一部分时,省略第一个参数标签,否则需要添加第一个参数标签

推荐

// 参数构成语句一部分,省略第一个参数标签
x.addSubview(y)

// 参数不构成语句一部分,不省略第一个参数标签
view.dismiss(animated: false)
2.6.5 其余情况下,给除第一个参数外的参数都添加标签


2.7 方法命名:不要使用冗余的单词,特别是与参数及参数标签重复

推荐

func remove(_ member: Element) -> Element?

不推荐

func removeElement(_ member: Element) -> Element?


2.8 命名出现缩写词,缩写词要么全部大写,要么全部小写,以首字母大小写为准

推荐

let urlRouterString = "https://xxxxx"

let htmlString = "xxxx"

class HTMLModel {
    /* ... */
}

struct URLRouter {
    /* ... */
}

不推荐

let uRLRouterString = "https://xxxxx"

let hTMLString = "xxxx"

class HtmlModel {
    /* ... */
}

struct UrlRouter {
    /* ... */
}


2.9 Bool类型命名:用is最为前缀

推荐

var isString: Bool = true


2.10 枚举定义尽量简写,不要包括类型前缀

推荐

public enum UITableViewRowAnimation : Int {
    case fade

    case right // slide in from right (or out to right)

    case left

    case top

    case bottom

    case none // available in iOS 3.0

    case middle // available in iOS 3.2.  attempts to keep cell centered in the space it will/did occupy

    case automatic // available in iOS 5.0.  chooses an appropriate animation style for you
}


2.11 协议命名

协议规则(from Swift API Design Guidelines)

2.11.1 如果协议描述的是协议做的事应该命名为名词(eg. Collection)

推荐

protocol TableViewSectionProvider {
    func rowHeight(at row: Int) -> CGFloat
    var numberOfRows: Int { get }
    /* ... */
}
2.11.2 如果协议描述的是能力,需添加后缀able或 ing (eg. Equatable、 ProgressReporting)

推荐

protocol Loggable {
    func logCurrentState()
    /* ... */
}

protocol Equatable {

    func ==(lhs: Self, rhs: Self) -> bool {
        /* ... */
    }
}
2.11.3 如果已经定义类,需要给类定义相关协议,则添加Protocol后缀

推荐

protocol InputTextViewProtocol {
    func sendTrackingEvent()
    func inputText() -> String
    /* ... */
}


相关阅读:【Swift编码规范】(下篇)

网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者胡波授权发布。