Swift 代码规范中文-Swift Style Guide

Swift Style Guide

Swift代码规范指南

Make sure to read Apple's API Design Guidelines.
确保阅读苹果的API设计指南

Specifics from these guidelines + additional remarks are mentioned below.
下文提到了这些指南中的具体细节+补充意见。

This guide was last updated for Swift 4.0 on February 14, 2018.
本指南最后一次针对Swift 4.0更新是在2018年2月14日。

Table Of Contents

目录

  • Swift Style Guide
  • Swift代码规范指南
      1. Code Formatting
      1. 代码格式
      1. Naming
      1. 命名
      1. Coding Style
      1. 编码规范
      • 3.1 General
      • 3.1 概述
      • 3.2 Access Modifiers
      • 3.2 访问修饰符
      • 3.3 Custom Operators
      • 3.3 自定义操作符
      • 3.4 Switch Statements and enums
      • 3.4 Switch语句和枚举
      • 3.5 Optionals
      • 3.5 可选类型
      • 3.6 Protocols
      • 3.6 协议
      • 3.7 Properties
      • 3.7 属性
      • 3.8 Closures
      • 3.8 闭包
      • 3.9 Arrays
      • 3.9 数组
      • 3.10 Error Handling
      • 3.10 错误处理
      • 3.11 Using guard Statements
      • 3.11 使用 guard 语句
      1. Documentation/Comments
      1. 文档/注释
      • 4.1 Documentation
      • 4.1 文档
      • 4.2 Other Commenting Guidelines
      • 4.2 其他注释原则

1. Code Formatting

1. 代码格式

  • 1.1 Use 4 spaces for tabs.

  • 1.1 使用四个空格进行缩进。

  • 1.2 Avoid uncomfortably long lines with a hard maximum of 160 characters per line (Xcode->Preferences->Text Editing->Page guide at column: 160 is helpful for this)

  • 1.2 每行最多160个字符,这样可以避免一行过长 (Xcode->Preferences->Text Editing->Page guide at column: 设置成160行即可)

译者注:大可不必设置,自己API设计好一点即可,调用他人的API也无法避免行数过长,真的超了设置也起不了什么作用,再说Xcode本身有自动换行。

  • 1.3 Ensure that there is a newline at the end of every file.
  • 1.3 确保每个文件结尾都有空白行。

译者注:Xcode12开始,每个文件结尾都自动有偏移量了,开发者自己不必加空行。

  • 1.4 Ensure that there is no trailing whitespace anywhere (Xcode->Preferences->Text Editing->Automatically trim trailing whitespace + Including whitespace-only lines).
  • 1.4 确保每行都不以空白字符作为结尾 (Xcode->Preferences->Text Editing->Automatically trim trailing whitespace + Including whitespace-only lines)。

译者注:这样能避免修改代码过程中因多个空格、少个空格而产生不必要的文件差异。如果项目里的每个开发人员都设置最好,否则只要有人不设置,他提交的代码还是会出现结尾有空白字符,而其他设置过的人触碰到该行代码,空格自动消失,产生的差异还无法回退。

  • 1.5 Do not place opening braces on new lines - we use the 1TBS style.
  • 1.5 左大括号不用另起一行。
class SomeClass {
    func someMethod() {
        if x == y {
            /* ... */
        } else if x == z {
            /* ... */
        } else {
            /* ... */
        }
    }

    /* ... */
}
  • 1.6 When writing a type for a property, constant, variable, a key for a dictionary, a function argument, a protocol conformance, or a superclass, don't add a space before the colon.
  • 1.6 当在写一个变量类型,一个字典里的主键,一个函数的参数,遵从一个协议,或一个父类,不用在分号前添加空格。
// specifying type
let pirateViewController: PirateViewController

// dictionary syntax (note that we left-align as opposed to aligning colons)
let ninjaDictionary: [String: AnyObject] = [
    "fightLikeDairyFarmer": false,
    "disgusting": true
]

// declaring a function
func myFunction<T, U: SomeProtocol>(firstArgument: U, secondArgument: T) where T.RelatedType == U {
    /* ... */
}

// calling a function
someFunction(someArgument: "Kitten")

// superclasses
class PirateViewController: UIViewController {
    /* ... */
}

// protocols
extension PirateViewController: UITableViewDataSource {
    /* ... */
}
  • 1.7 In general, there should be a space following a comma.
  • 1.7 通常来说,要在逗号后面加空格。
let myArray = [1, 2, 3, 4, 5]
  • 1.8 There should be a space before and after a binary operator such as +, ==, or ->. There should also not be a space after a ( and before a ).
  • 1.8 在二元运算符前后要加空格,例如+, ==, 或 ->。而在左括号( 后面和有括号)的前面不要加空格。
let myValue = 20 + (30 / 2) * 3
if 1 + 1 == 3 {
    fatalError("The universe is broken.")
}
func pancake(with syrup: Syrup) -> Pancake {
    /* ... */
}
  • 1.9 We follow Xcode's recommended indentation style (i.e. your code should not change if CTRL-I is pressed). When declaring a function that spans multiple lines, prefer using that syntax to which Xcode, as of version 7.3, defaults.
  • 1.9 遵守Xcode内置的缩进格式 (如果已经遵守,按下Control+i键,代码格式不会有变化). 当声明的一个函数需要跨多行时,推荐使用Xcode默认的格式,目前Xcode 版本是 7.3。
// Xcode indentation for a function declaration that spans multiple lines
func myFunctionWithManyParameters(parameterOne: String,
                                  parameterTwo: String,
                                  parameterThree: String) {
    // Xcode indents to here for this kind of statement
    print("\(parameterOne) \(parameterTwo) \(parameterThree)")
}

// Xcode indentation for a multi-line `if` statement
if myFirstValue > (mySecondValue + myThirdValue)
    && myFourthValue == .someEnumValue {

    // Xcode indents to here for this kind of statement
    print("Hello, World!")
}
  • 1.10 When calling a function that has many parameters, put each argument on a separate line with a single extra indentation.
  • 1.10 当调用的函数有多个参数时,每一个参数另起一行,并比函数名多一个缩进。
someFunctionWithManyArguments(
    firstArgument: "Hello, I am a string",
    secondArgument: resultFromSomeFunction(),
    thirdArgument: someOtherLocalProperty)

译者注:其实我个人不建议参数换行,除非参数需要突出让阅读者注意,否则适得其反,总之慎用!慎用!慎用!
很多开发者不仅喜欢参数换行,并且第一个参数不换行,格式对齐后,整个代码块挤在了右边一小块,凌乱不堪,阅读起来真难受。

什么鬼?这种代码都写得出...

所有参数都换行,比上面好看很多。

个人更倾向于不换行,纵向阅读容易理解这里主要就两句代码,一是获取股票持仓者,通过闭包回调,二是闭包内处理回调数据。
有必要的情况下可以使用参数换行,但一定不要出现第一张图那种凌乱不堪的代码。

  • 1.11 When dealing with an implicit array or dictionary large enough to warrant splitting it into multiple lines, treat the [ and ] as if they were braces in a method, if statement, etc. Closures in a method should be treated similarly.
  • 1.11 当遇到需要处理的数组或字典内容较多需要多行显示时,需把 [] 类似于方法体里的括号, 方法体里的闭包也要做类似处理。
someFunctionWithABunchOfArguments(
    someStringArgument: "hello I am a string",
    someArrayArgument: [
        "dadada daaaa daaaa dadada daaaa daaaa dadada daaaa daaaa",
        "string one is crazy - what is it thinking?"
    ],
    someDictionaryArgument: [
        "dictionary key 1": "some value 1, but also some more text here",
        "dictionary key 2": "some value 2"
    ],
    someClosure: { parameter1 in
        print(parameter1)
    })
  • 1.12 Prefer using local constants or other mitigation techniques to avoid multi-line predicates where possible.
  • 1.12 应尽量避免出现多行断言,可使用本地变量或其他策略。
// PREFERRED
let firstCondition = x == firstReallyReallyLongPredicateFunction()
let secondCondition = y == secondReallyReallyLongPredicateFunction()
let thirdCondition = z == thirdReallyReallyLongPredicateFunction()
if firstCondition && secondCondition && thirdCondition {
    // do something
}

// NOT PREFERRED
if x == firstReallyReallyLongPredicateFunction()
    && y == secondReallyReallyLongPredicateFunction()
    && z == thirdReallyReallyLongPredicateFunction() {
    // do something
}

2. Naming

2. 命名

  • 2.1 There is no need for Objective-C style prefixing in Swift (e.g. use just GuybrushThreepwood instead of LIGuybrushThreepwood).
  • 2.1 在Swift中不用如Objective-C式 一样添加前缀 (如使用 GuybrushThreepwoode 而不是 LIGuybrushThreepwood)。

译者注:还是有很多人写Swift习惯用前缀,那是因为没有明白Swift的真谛,Swift不同框架即便用同个类名也不会冲突,在同一个文件中使用到二者,需要引用对应框架名来区分。

  • 2.2 Use PascalCase for type names (e.g. struct, enum, class, typedef, associatedtype, etc.).

  • 2.2 使用帕斯卡拼写法(又名大骆驼拼写法首字母大写)为类型命名 (如 struct, enum, class, typedef, associatedtype 等)。

  • 2.3 Use camelCase (initial lowercase letter) for function, method, property, constant, variable, argument names, enum cases, etc.

  • 2.3 使用小骆驼拼写法 (首字母小写) 为函数方法变量常量参数等命名。

  • 2.4 When dealing with an acronym or other name that is usually written in all caps, actually use all caps in any names that use this in code. The exception is if this word is at the start of a name that needs to start with lowercase - in this case, use all lowercase for the acronym.

  • 2.4 首字母缩略词在命名中一般来说都是全部大写,例外的情形是如果首字母缩略词是一个命名的开始部分,而这个命名需要小写字母作为开头,这种情形下首字母缩略词全部小写。

// "HTML" is at the start of a constant name, so we use lowercase "html"
let htmlBodyContent: String = "<p>Hello, World!</p>"
// Prefer using ID to Id
let profileID: Int = 1
// Prefer URLFinder to UrlFinder
class URLFinder {
    /* ... */
}
  • 2.5 All constants that are instance-independent should be static. All such static constants should be placed in a marked section of their class, struct, or enum. For classes with many constants, you should group constants that have similar or the same prefixes, suffixes and/or use cases.
  • 2.5 所有与实例无关的常量都应该是static。所有这些static常数都应放置在其classstructenum的标记部分。对于具有许多常量的类,您应该对具有相似或相同前缀、后缀和/或用例的常量进行分组。
// PREFERRED    
class MyClassName {
    // MARK: - Constants
    static let buttonPadding: CGFloat = 20.0
    static let indianaPi = 3
    static let shared = MyClassName()
}

// NOT PREFERRED
class MyClassName {
    // Don't use `k`-prefix
    static let kButtonPadding: CGFloat = 20.0

    // Don't namespace constants
    enum Constant {
        static let indianaPi = 3
    }
}

译者注:苹果代码规范指南里每一点都有其意义及精髓存在,需要用心去体会其设计意义。否则每个人都按自己的方式,或者沿用其他语言的习惯来写,代码将风格迥异。我甚至看到有一篇译文,枉顾苹果的代码示例,固执己见推荐使用k作为前缀。k作为前缀是OC的宏定义的写法,在Swift中不推荐这种写法。

  • 2.6 For generics and associated types, use a PascalCase word that describes the generic. If this word clashes with a protocol that it conforms to or a superclass that it subclasses, you can append a Type suffix to the associated type or generic name.
  • 2.6 对于泛型和相关类型,请使用PascalCase单词(大驼峰式命名)描述泛型。如果此词与其遵循的协议名继承类的超类名冲突,您可以在关联类型或泛型名称中添加Type后缀。
class SomeClass<Model> { /* ... */ }
protocol Modelable {
    associatedtype Model
}
protocol Sequence {
    associatedtype IteratorType: Iterator
}
  • 2.7 Names should be descriptive and unambiguous.
  • 2.7 姓名应具有描述性和明确性。
// PREFERRED
class RoundAnimatingButton: UIButton { /* ... */ }

// NOT PREFERRED
class CustomButton: UIButton { /* ... */ }
  • 2.8 Do not abbreviate, use shortened names, or single letter names.
  • 2.8 不要缩写、简写命名或用单个字母命名。
// PREFERRED
class RoundAnimatingButton: UIButton {
    let animationDuration: NSTimeInterval

    func startAnimating() {
        let firstSubview = subviews.first
    }

}

// NOT PREFERRED
class RoundAnimating: UIButton {
    let aniDur: NSTimeInterval

    func srtAnmating() {
        let v = subviews.first
    }
}
  • 2.9 Include type information in constant or variable names when it is not obvious otherwise.
  • 2.9 当常量或变量名称不能明显地表明类型时,应当将类型信息包含在命名中。
// PREFERRED
class ConnectionTableViewCell: UITableViewCell {
    let personImageView: UIImageView

    let animationDuration: TimeInterval

    // it is ok not to include string in the ivar name here because it's obvious
    // that it's a string from the property name
    let firstName: String

    // though not preferred, it is OK to use `Controller` instead of `ViewController`
    let popupController: UIViewController
    let popupViewController: UIViewController

    // when working with a subclass of `UIViewController` such as a table view
    // controller, collection view controller, split view controller, etc.,
    // fully indicate the type in the name.
    let popupTableViewController: UITableViewController

    // when working with outlets, make sure to specify the outlet type in the
    // property name.
    @IBOutlet weak var submitButton: UIButton!
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var nameLabel: UILabel!

}

// NOT PREFERRED
class ConnectionTableViewCell: UITableViewCell {
    // this isn't a `UIImage`, so shouldn't be called image
    // use personImageView instead
    let personImage: UIImageView

    // this isn't a `String`, so it should be `textLabel`
    let text: UILabel

    // `animation` is not clearly a time interval
    // use `animationDuration` or `animationTimeInterval` instead
    let animation: TimeInterval

    // this is not obviously a `String`
    // use `transitionText` or `transitionString` instead
    let transition: String

    // this is a view controller - not a view
    let popupView: UIViewController

    // as mentioned previously, we don't want to use abbreviations, so don't use
    // `VC` instead of `ViewController`
    let popupVC: UIViewController

    // even though this is still technically a `UIViewController`, this property
    // should indicate that we are working with a *Table* View Controller
    let popupViewController: UITableViewController

    // for the sake of consistency, we should put the type name at the end of the
    // property name and not at the start
    @IBOutlet weak var btnSubmit: UIButton!
    @IBOutlet weak var buttonSubmit: UIButton!

    // we should always have a type in the property name when dealing with outlets
    // for example, here, we should have `firstNameLabel` instead
    @IBOutlet weak var firstName: UILabel!
}

译者注:许多开发人员在属性命名方面真的很随意,也不学学苹果系统框架中是怎么命名的,让其他开发阅读起来有多累!

  • 2.10 When naming function arguments, make sure that the function can be read easily to understand the purpose of each argument.

  • 2.10 命名函数参数时,请确保函数易于阅读以理解每个参数的用途。

  • 2.11 As per Apple's API Design Guidelines, a protocol should be named as nouns if they describe what something is doing (e.g. Collection) and using the suffixes able, ible, or ing if it describes a capability (e.g. Equatable, ProgressReporting). If neither of those options makes sense for your use case, you can add a Protocol suffix to the protocol's name as well. Some example protocols are below.

  • 2.11 根据苹果的API设计指南,如果protocol描述了正在做的事情(例如Collection)并使用后缀ableibleing如果它描述了一种功能(例如EquatableProgressReporting)。如果这两个选项对您的用例都毫无意义,您也可以在协议名称中添加协议后缀。以下是一些协议示例。

// here, the name is a noun that describes what the protocol does
protocol TableViewSectionProvider {
    func rowHeight(at row: Int) -> CGFloat
    var numberOfRows: Int { get }
    /* ... */
}

// here, the protocol is a capability, and we name it appropriately
protocol Loggable {
    func logCurrentState()
    /* ... */
}

// suppose we have an `InputTextView` class, but we also want a protocol
// to generalize some of the functionality - it might be appropriate to
// use the `Protocol` suffix here
protocol InputTextViewProtocol {
    func sendTrackingEvent()
    func inputText() -> String
    /* ... */
}

3. Coding Style

3. 编码风格

3.1 General

3.1 概述

  • 3.1.1 Prefer let to var whenever possible.

  • 3.1.1 尽可能使用let(能用let就不要用var

  • 3.1.2 Prefer the composition of map, filter, reduce, etc. over iterating when transforming from one collection to another. Make sure to avoid using closures that have side effects when using these methods.

  • 3.1.2 从一个集合转换为另一个集合时,推荐使用mapfilterreduce等。从一个集合转换到另一个集合时过度迭代。使用这些方法时,请确保避免使用有副作用的闭包。

// PREFERRED
let stringOfInts = [1, 2, 3].flatMap { String($0) }
// ["1", "2", "3"]

// NOT PREFERRED
var stringOfInts: [String] = []
for integer in [1, 2, 3] {
    stringOfInts.append(String(integer))
}

// PREFERRED
let evenNumbers = [4, 8, 15, 16, 23, 42].filter { $0 % 2 == 0 }
// [4, 8, 16, 42]

// NOT PREFERRED
var evenNumbers: [Int] = []
for integer in [4, 8, 15, 16, 23, 42] {
    if integer % 2 == 0 {
        evenNumbers.append(integer)
    }
}
  • 3.1.3 Prefer not declaring types for constants or variables if they can be inferred anyway.
  • 3.1.3 如果可以推断出常量或变量类型,最好不要声明它们的类型。
// 推荐
let url = "xxx"
let port = 8080

// 不推荐
let url: String = "xxx"
let port: Int = 8080
  • 3.1.4 If a function returns multiple values, prefer returning a tuple to using inout arguments (it’s best to use labeled tuples for clarity on what you’re returning if it is not otherwise obvious). If you use a certain tuple more than once, consider using a typealias. If you’re returning 3 or more items in a tuple, consider using a struct or class instead.
  • 3.1.4 如果函数返回多个值,倾向于返回元组,而不是使用inout参数(如果元组的项的含义不明显,最好使用带标签的元组来明确要返回的内容)。如果您多次使用某个元组,请考虑使用typealias。如果您要以元组返回3个或更多项目,请考虑改用structclass
func pirateName() -> (firstName: String, lastName: String) {
    return ("Guybrush", "Threepwood")
}

let name = pirateName()
let firstName = name.firstName
let lastName = name.lastName
  • 3.1.5 Be wary of retain cycles when creating delegates/protocols for your classes; typically, these properties should be declared weak.

  • 3.1.5 为类创建委托/协议时,请小心保留周期;通常,这些属性应声明为weak

  • 3.1.6 Be careful when calling self directly from an escaping closure as this can cause a retain cycle - use a capture list when this might be the case:
    3.1.6 直接从转义闭包调用self时要小心,因为这可能导致保留循环 - 在这种情况下使用捕获列表

myFunctionWithEscapingClosure() { [weak self] (error) -> Void in
    // you can do this

    self?.doSomething()

    // or you can do this

    guard let strongSelf = self else {
        return
    }

    strongSelf.doSomething()
}

译者注:Swift4.2之后建议这么写 guard let self = self else { return }
见:https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade-self-from-weak-to-strong.md#relying-on-a-compiler-bug

  • 3.1.7 Don't use labeled breaks.

  • 3.1.7 Switch 模块中不用显式使用break

  • 3.1.8 Don't place parentheses around control flow predicates.

  • 3.1.8 控制流断言不用加小括号。

// PREFERRED
if x == y {
    /* ... */
}

// NOT PREFERRED
if (x == y) {
    /* ... */
}
  • 3.1.9 Avoid writing out an enum type where possible - use shorthand.
  • 3.1.9 使用枚举时,尽可能不要把类型写出来。
// PREFERRED
imageView.setImageWithURL(url, type: .person)

// NOT PREFERRED
imageView.setImageWithURL(url, type: AsyncImageView.Type.person)
  • 3.1.10 Don’t use shorthand for class methods since it is generally more difficult to infer the context from class methods as opposed to enums.
  • 3.1.10 不要对类方法使用简写,因为从类方法推断上下文通常比枚举更难。
// PREFERRED
imageView.backgroundColor = UIColor.white

// NOT PREFERRED
imageView.backgroundColor = .white

译者注:这里我觉得UIColor类方法简写还是能使代码更简洁的,我习惯简写,但其他类方法还是看具体而定,如果简写不能很好地推断上下文,那还是建议加上类名为好。

  • 3.1.11 Prefer not writing self. unless it is required.

  • 3.1.11 尽量不要使用self.,除非必要(闭包内必须使用self.)。

  • 3.1.12 When writing methods, keep in mind whether the method is intended to be overridden or not. If not, mark it as final, though keep in mind that this will prevent the method from being overwritten for testing purposes. In general, final methods result in improved compilation times, so it is good to use this when applicable. Be particularly careful, however, when applying the final keyword in a library since it is non-trivial to change something to be non-final in a library as opposed to have changing something to be non-final in your local project.

  • 3.1.12 在编写方法时,需要衡量该方法是否将来会被重写,如果不希望被子类重写,请使用final关键词修饰。一般来说,final修饰的方法可以得到编译速度的优化,在有必要时,使用final是不错的选择。但特别要注意的是,相比在本地项目来说,在库中将final改为非final并非易事。

  • 3.1.13 When using a statement such as else, catch, etc. that follows a block, put this keyword on the same line as the block. Again, we are following the 1TBS style here. Example if/else and do/catch code is below.

  • 3.1.13 在代码块后面使用else, catch等语句时,将关键词与代码块放在同一行。我们在这里遵循 1TBS style。下面有if/else and do/catch的示例。

if someBoolean {
    // do something
} else {
    // do something else
}

do {
    let fileContents = try readFile("filename.txt")
} catch {
    print(error)
}
  • 3.1.14 Prefer static to class when declaring a function or property that is associated with a class as opposed to an instance of that class. Only use class if you specifically need the functionality of overriding that function or property in a subclass, though consider using a protocol to achieve this instead.

  • 3.1.14 在声明与类相关联的函数或属性而不是该类的实例时,优先使用 static 而非 class。 仅当您特别需要在子类中覆盖该函数或属性的功能时才使用 class,尽管考虑使用 protocol 来实现这一点。

  • 3.1.15 If you have a function that takes no arguments, has no side effects, and returns some object or value, prefer using a computed property instead.

  • 3.1.15 如果您的函数没有参数,没有副作用,并返回一些对象或值,则更喜欢使用计算属性。

译者注:这里要好好理解副作用的意思,是指一些不应该有的,或让人意料之外的作用。下面我列举一些代码示例。

// 推荐
struct Square {
    var side: CGFloat = 1.0
    // 获取周长,使用计算属性
    var girth: CGFloat {
        return side * 4
    }
}
// 不推荐
struct Square {
    var side: CGFloat = 1.0
    // 无参数、无`副作用`,返回周长,不推荐使用函数
    func girth() -> CGFloat {
        return side * 4
    }
}

// 推荐
class Square {
    var side: CGFloat = 1.0
    // 将边长缩小一半,并返回缩小后的周长,使用函数
    func halfGirth() -> CGFloat {
        self.side = side * 0.5
        return side * 4
    }
}
// 不推荐
class Square {
    var side: CGFloat = 1.0
    // 这里存在`副作用`,让人意想不到,不推荐使用计算属性
    var halfGirth: CGFloat {
        self.side = side * 0.5
        return side * 4
    }
}

3.2 Access Modifiers

3.2 访问修饰符

  • 3.2.1 Write the access modifier keyword first if it is needed.
  • 3.2.1 如果需要,将访问修饰符放在第一位。
// PREFERRED
private static let myPrivateNumber: Int

// NOT PREFERRED
static private let myPrivateNumber: Int
  • 3.2.2 The access modifier keyword should not be on a line by itself - keep it inline with what it is describing.
  • 3.2.2 访问修饰符不应单独成行,应与修饰的内容放在同一行。
// PREFERRED
open class Pirate {
    /* ... */
}

// NOT PREFERRED
open
class Pirate {
    /* ... */
}
  • 3.2.3 In general, do not write the internal access modifier keyword since it is the default.

  • 3.2.3 一般来说,不要编写internal访问修饰符关键字,因为它是默认的。

  • 3.2.4 If a property needs to be accessed by unit tests, you will have to make it internal to use @testable import ModuleName. If a property should be private, but you declare it to be internal for the purposes of unit testing, make sure you add an appropriate bit of documentation commenting that explains this. You can make use of the - warning: markup syntax for clarity as shown below.

  • 3.2.4 如果需要通过单元测试访问属性,在单元测试文件中使用@testable import ModuleName,以此来访问声明为internal的类型。如果一个属性应该是private的,但为了单元测试的目的,您声明它是internal的,请确保添加适当的文档注释来解释这一点。您可以使用- warning:标记语法来保持清晰,如下所示。

/**
 This property defines the pirate's name.
 - warning: Not `private` for `@testable`.
 */
let pirateName = "LeChuck"
  • 3.2.5 Prefer private to fileprivate where possible.

  • 3.2.5 能用private的,就不要用fileprivate

  • 3.2.6 When choosing between public and open, prefer open if you intend for something to be subclassable outside of a given module and public otherwise. Note that anything internal and above can be subclassed in tests by using @testable import, so this shouldn't be a reason to use open. In general, lean towards being a bit more liberal with using open when it comes to libraries, but a bit more conservative when it comes to modules in a codebase such as an app where it is easy to change things in multiple modules simultaneously.

  • 3.2.6publicopen之间怎么选择?如果您打算将某些东西在给定模块之外进行子类化时,使用open,否则使用public。请注意,任何internal或以上级别的内容,在单元测试中都可以通过@testable import来使用,无需将其声明为open。一般来说,在库方面,倾向于更自由地使用open,但像app这种可以轻松地同时修改多个模块的模块中,则倾向于更保守一点。

3.3 Custom Operators

3.3 自定义操作符

Prefer creating named functions to custom operators.
不推荐使用自定义操作符,如果需要创建函数来替代。

If you want to introduce a custom operator, make sure that you have a very good reason why you want to introduce a new operator into global scope as opposed to using some other construct.
如果您想引入自定义运算符,请确保您有很好的理由,为什么您希望将新运算符引入全局范围,而不使用其他构造。

You can override existing operators to support new types (especially ==). However, your new definitions must preserve the semantics of the operator. For example, == must always test equality and return a boolean.
您可以重写已存在的运算符来支持新的类型(特别是==),但无论如何,你都得保留运算符原来的语义,例如,==必须是用来测试是否相等并返回布尔值。

译者注:相信很多人也不会去重写运算符,更多的是使用自定义方法,反正不要去踩这个坑。

3.4 Switch Statements and enums

3.4 Switch语句和enum

  • 3.4.1 When using a switch statement that has a finite set of possibilities (enum), do NOT include a default case. Instead, place unused cases at the bottom and use the break keyword to prevent execution.

  • 3.4.1 使用有限集合(enum)的switch语句时,不要包含default。反之,switch语句的末尾用default涵盖其他情况。

  • 3.4.2 Since switch cases in Swift break by default, do not include the break keyword if it is not needed.

  • 3.4.2 switch语句在Swift中默认是会break的,因此不需要添加break(OC中需要在每个case末尾添加break)。

  • 3.4.3 The case statements should line up with the switch statement itself as per default Swift standards.

  • 3.4.3 根据默认Swift标准,case语句应与switch本身对齐。

  • 3.4.4 When defining a case that has an associated value, make sure that this value is appropriately labeled as opposed to just types (e.g. case hunger(hungerLevel: Int) instead of case hunger(Int)).

  • 3.4.4 在定义有关联值的case时,请确保该值有恰当的名称,而不只有类型(例如,case hunger(hungerLevel: Int)而不是case hunger(Int))。

enum Problem {
    case attitude
    case hair
    case hunger(hungerLevel: Int)
}

func handleProblem(problem: Problem) {
    switch problem {
    case .attitude:
        print("At least I don't have a hair problem.")
    case .hair:
        print("Your barber didn't know when to stop.")
    case .hunger(let hungerLevel):
        print("The hunger level is \(hungerLevel).")
    }
}
  • 3.4.5 Prefer lists of possibilities (e.g. case 1, 2, 3:) to using the fallthrough keyword where possible).

  • 3.4.5 推荐使用多个可能性(例如case 1, 2, 3:),而不用fallthrough

  • 3.4.6 If you have a default case that shouldn't be reached, preferably throw an error (or handle it some other similar way such as asserting).

  • 3.4.6 如果default的情况不应该被触发,最好抛出错误(或以其他类似方式处理它,例如断言)。

func handleDigit(_ digit: Int) throws {
    switch digit {
    case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
        print("Yes, \(digit) is a digit!")
    default:
        throw Error(message: "The given number was not a digit.")
    }
}

3.5 Optionals

3.5 可选

  • 3.5.1 The only time you should be using implicitly unwrapped optionals is with @IBOutlets. In every other case, it is better to use a non-optional or regular optional property. Yes, there are cases in which you can probably "guarantee" that the property will never be nil when used, but it is better to be safe and consistent. Similarly, don't use force unwraps.

  • 3.5.1 唯一应该使用隐式解包可选类型的场景是与@IBOutlet结合使用。在所有其他情况下,最好使用非可选显式可选属性(这样可以保持一致性和程序更加健壮)。虽然在某些情况下,您可能可以“保证”属性在使用时永远不会为nil,但最好是安全和一致。同样,不要强制解包

  • 3.5.2 Don't use as! or try!.

  • 3.5.2 不要使用as!try!

  • 3.5.3 If you don't plan on actually using the value stored in an optional, but need to determine whether or not this value is nil, explicitly check this value against nil as opposed to using if let syntax.

  • 3.5.3 如果您不打算可选类型中存储的值,只是需要判断值是否为nil,应直接将其与nil比较,而不是使用if let语法。

// PREFERRED
if someOptional != nil {
    // do something
}

// NOT PREFERRED
if let _ = someOptional {
    // do something
}
  • 3.5.4 Don't use unowned. You can think of unowned as somewhat of an equivalent of a weak property that is implicitly unwrapped (though unowned has slight performance improvements on account of completely ignoring reference counting). Since we don't ever want to have implicit unwraps, we similarly don't want unowned properties.
  • 3.5.4 不要使用unowned。您可以将unowned属性看做是一个强制解包的weak属性(尽管unowned是完全忽略引用计数,性能略有提升)。由于我们不推荐强制解包,因此同样不推荐使用unowned属性。
// PREFERRED
weak var parentViewController: UIViewController?

// NOT PREFERRED
weak var parentViewController: UIViewController!
unowned var parentViewController: UIViewController
  • 3.5.5 When unwrapping optionals, use the same name for the unwrapped constant or variable where appropriate.
  • 3.5.5 对可选属性解包时,对解开的常量或变量使用相同的名称。
guard let myValue = myValue else {
    return
}
  • 3.5.6 Use XCTUnwrap instead of forced unwrapping in tests.
  • 3.5.6 在单元测试中,对可选类型使用XCTUnwrap,而不用强制解包。
func isEvenNumber(_ number: Int) -> Bool {
    return number % 2 == 0
}

// PREFERRED
func testWithXCTUnwrap() throws {
    let number: Int? = functionThatReturnsOptionalNumber()
    XCTAssertTrue(isEvenNumber(try XCTUnwrap(number)))
}

// NOT PREFERRED
func testWithForcedUnwrap() {
    let number: Int? = functionThatReturnsOptionalNumber()
    XCTAssertTrue(isEvenNumber(number!)) // may crash the simulator
}

3.6 Protocols

3.6 协议

When implementing protocols, there are two ways of organizing your code:
实现协议时,有两种方式来组织代码:

  1. Using // MARK: comments to separate your protocol implementation from the rest of your code
  2. Using an extension outside your class/struct implementation code, but in the same source file
  3. 使用// MARK:注释将您的协议实现与代码的其余部分分开
  4. class/struct实现代码之外使用扩展名,但在同一源代码文件中

Keep in mind that when using an extension, however, the methods in the extension can't be overridden by a subclass, which can make testing difficult. If this is a common use case, it might be better to stick with method #1 for consistency. Otherwise, method #2 allows for cleaner separation of concerns.
请记住,在使用扩展时,扩展中的方法不能被子类覆盖,否则可能会使测试变得困难。如果这种情况经常发生,为了保持一致性,最好坚持使用第一种方式。否则使用第二种方式,会使代码分离得更干净。

Even when using method #2, add // MARK: statements anyway for easier readability in Xcode's method/property/class/etc. list UI.
尽管使用第二种方式,也要添加// MARK:语句,以便在Xcode的method/property/class列表界面中更容易阅读。

3.7 Properties

3.7 属性

  • 3.7.1 If making a read-only, computed property, provide the getter without the get {} around it.
  • 3.7.1 如果要创建一个read-only计算属性,请提供getter但无需使用get {}包住它。
var computedProperty: String {
    if someBool {
        return "I'm a mighty pirate!"
    }
    return "I'm selling these fine leather jackets."
}
  • 3.7.2 When using get {}, set {}, willSet, and didSet, indent these blocks.

  • 3.7.2 使用get {}set {}willSetdidSet 时,注意缩进代码块。

  • 3.7.3 Though you can create a custom name for the new or old value for willSet/didSet and set, use the standard newValue/oldValue identifiers that are provided by default.

  • 3.7.3 尽管您可以为 willSet/didSetset 的新值或旧值创建自定义名称,但推荐使用默认提供的标准名称newValue/oldValue

var storedProperty: String = "I'm selling these fine leather jackets." {
    willSet {
        print("will set to \(newValue)")
    }
    didSet {
        print("did set from \(oldValue) to \(storedProperty)")
    }
}

var computedProperty: String  {
    get {
        if someBool {
            return "I'm a mighty pirate!"
        }
        return storedProperty
    }
    set {
        storedProperty = newValue
    }
}
  • 3.7.4 You can declare a singleton property as follows:
  • 3.7.4 您可以用下面的方式声明单例。
class PirateManager {
    static let shared = PirateManager()

    /* ... */
}

3.8 Closures

3.8 闭包

  • 3.8.1 If the types of the parameters are obvious, it is OK to omit the type name, but being explicit is also OK. Sometimes readability is enhanced by adding clarifying detail and sometimes by taking repetitive parts away - use your best judgment and be consistent.
  • 3.8.1 如果参数的类型明显,可以省略类型名称,当然显式类型也可以。有时可以通过添加澄清细节来提高可读性,有时通过删除重复的部分来提高可读性——使用你的最佳判断力并保持一致性。
// omitting the type
doSomethingWithClosure() { response in
    print(response)
}

// explicit type
doSomethingWithClosure() { response: NSURLResponse in
    print(response)
}

// using shorthand in a map statement
[1, 2, 3].flatMap { String($0) }

译者注:闭包中参数如果能清楚地推测出类型,可以不用写类型,否则还是把类型写出来提高可读性。

  • 3.8.2 If specifying a closure as a type, you don’t need to wrap it in parentheses unless it is required (e.g. if the type is optional or the closure is within another closure). Always wrap the arguments in the closure in a set of parentheses - use () to indicate no arguments and use Void to indicate that nothing is returned.
  • 3.8.2 如果将闭包指定为类型,不需要将其包装在括号中,除非有必要(例如,如果类型是可选的或闭包在另一个闭包中)。始终将闭包中的参数包裹在一组括号中 - 使用 () 表示没有参数,使用 Void 表示不返回任何内容。
let completionBlock: (Bool) -> Void = { (success) in
    print("Success? \(success)")
}

let completionBlock: () -> Void = {
    print("Completed!")
}

let completionBlock: (() -> Void)? = nil
  • 3.8.3 Keep parameter names on same line as the opening brace for closures when possible without too much horizontal overflow (i.e. ensure lines are less than 160 characters).

  • 3.8.3 在没有太多水平溢出的情况下,尽可能将参数名称与闭包的左大括号保持在同一行(即确保行少于 160 个字符)。

  • 3.8.4 Use trailing closure syntax unless the meaning of the closure is not obvious without the parameter name (an example of this could be if a method has parameters for success and failure closures).

  • 3.8.4 使用尾随闭包语法,除非闭包的含义在没有参数名称的情况下不明显(例如,如果方法具有成功和失败闭包的参数)。

// trailing closure
doSomething(1.0) { (parameter1) in
    print("Parameter 1 is \(parameter1)")
}

// no trailing closure
doSomething(1.0, success: { (parameter1) in
    print("Success with \(parameter1)")
}, failure: { (parameter1) in
    print("Failure with \(parameter1)")
})

译者注:其实Xcode中回车补全闭包参数时自动转化为尾随闭包了,有必要的情况下可以自己手写补全闭包。

3.9 Arrays

3.9 数组

  • 3.9.1 In general, avoid accessing an array directly with subscripts. When possible, use accessors such as .first or .last, which are optional and won’t crash. Prefer using a for item in items syntax when possible as opposed to something like for i in 0 ..< items.count. If you need to access an array subscript directly, make sure to do proper bounds checking. You can use for (index, value) in items.enumerated() to get both the index and the value.

  • 3.9.1 一般情况下,避免使用下标直接访问数组。 如果可能,请使用诸如.first.last之类的访问器,它们是可选的并且不会崩溃。 尽可能使用for item in items语法,而不是像for i in 0 ..< items.count这样的语法。 如果您需要直接访问数组下标,请确保进行适当的边界检查。 您可以在 items.enumerated()中使用 for (index, value) 来获取索引和值。

  • 3.9.2 Never use the += or + operator to append/concatenate to arrays. Instead, use .append() or .append(contentsOf:) as these are far more performant (at least with respect to compilation) in Swift's current state. If you are declaring an array that is based on other arrays and want to keep it immutable, instead of let myNewArray = arr1 + arr2, use let myNewArray = [arr1, arr2].joined().

  • 3.9.2 切勿使用 +=+ 运算符来追加/连接到数组。 相反,使用 .append().append(contentsOf:) 因为它们在 Swift 当前状态下的性能要高得多(至少在编译方面)。 如果您要声明一个基于其他数组的数组并希望使其保持不变,请使用let myNewArray = [arr1, arr2].joined()而不是let myNewArray = arr1 + arr2

译者注:这点我自己做的不好,jioned()真的很少用,相反数组+真的很好用,要舍弃真的有点舍不得,今后会多了解两者的使用场景。

3.10 Error Handling

3.10 错误处理

Suppose a function myFunction is supposed to return a String, however, at some point it can run into an error. A common approach is to have this function return an optional String? where we return nil if something went wrong.
假设函数myFunction 应该返回一个String,但是,在某些时候它可能会遇到错误。 常见的做法是让这个函数返回一个可选的 String?,如果出现问题,我们就返回 nil

Example:
例子:

func readFile(named filename: String) -> String? {
    guard let file = openFile(named: filename) else {
        return nil
    }

    let fileContents = file.read()
    file.close()
    return fileContents
}

func printSomeFile() {
    let filename = "somefile.txt"
    guard let fileContents = readFile(named: filename) else {
        print("Unable to open file \(filename).")
        return
    }
    print(fileContents)
}

Instead, we should be using Swift's try/catch behavior when it is appropriate to know the reason for the failure.
如果我们希望了解失败原因,可以使用Swift 的 try/catch

You can use a struct such as the following:
您可以使用struct,例如:

struct Error: Swift.Error {
    public let file: StaticString
    public let function: StaticString
    public let line: UInt
    public let message: String

    public init(message: String, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) {
        self.file = file
        self.function = function
        self.line = line
        self.message = message
    }
}

Example usage:
用法示例:

func readFile(named filename: String) throws -> String {
    guard let file = openFile(named: filename) else {
        throw Error(message: "Unable to open file named \(filename).")
    }

    let fileContents = file.read()
    file.close()
    return fileContents
}

func printSomeFile() {
    do {
        let fileContents = try readFile(named: filename)
        print(fileContents)
    } catch {
        print(error)
    }
}

There are some exceptions in which it does make sense to use an optional as opposed to error handling. When the result should semantically potentially be nil as opposed to something going wrong while retrieving the result, it makes sense to return an optional instead of using error handling.
在某些例外情况下,使用可选项确实比错误处理更有意义。 当结果在语义上 可能是 nil 而不是在检索结果时出现错误时,返回一个可选项比使用错误处理更有意义。

In general, if a method can "fail", and the reason for the failure is not immediately obvious if using an optional return type, it probably makes sense for the method to throw an error.
一般来说,如果一个方法可能会失败,并且如果使用可选返回类型,但失败的原因不是很明显,那么该方法抛出错误可能会更有意义。

3.11 Using guard Statements

3.11 使用guard 语句

  • 3.11.1 In general, we prefer to use an "early return" strategy where applicable as opposed to nesting code in if statements. Using guard statements for this use-case is often helpful and can improve the readability of the code.
  • 3.11.1 一般来说,我们更喜欢在适用的情况下使用“提前返回”策略,而不是在 if 语句中嵌套代码。 在这个用例中使用 guard 语句通常很有帮助,并且可以提高代码的可读性。
// PREFERRED
func eatDoughnut(at index: Int) {
    guard index >= 0 && index < doughnuts.count else {
        // return early because the index is out of bounds
        return
    }

    let doughnut = doughnuts[index]
    eat(doughnut)
}

// NOT PREFERRED
func eatDoughnut(at index: Int) {
    if index >= 0 && index < doughnuts.count {
        let doughnut = doughnuts[index]
        eat(doughnut)
    }
}
  • 3.11.2 When unwrapping optionals, prefer guard statements as opposed to if statements to decrease the amount of nested indentation in your code.
  • 3.11.2 展开可选项时,更喜欢使用 guard 语句而不是 if 语句,以减少代码中嵌套缩进的数量。
// PREFERRED
guard let monkeyIsland = monkeyIsland else {
    return
}
bookVacation(on: monkeyIsland)
bragAboutVacation(at: monkeyIsland)

// NOT PREFERRED
if let monkeyIsland = monkeyIsland {
    bookVacation(on: monkeyIsland)
    bragAboutVacation(at: monkeyIsland)
}

// EVEN LESS PREFERRED
if monkeyIsland == nil {
    return
}
bookVacation(on: monkeyIsland!)
bragAboutVacation(at: monkeyIsland!)
  • 3.11.3 When deciding between using an if statement or a guard statement when unwrapping optionals is not involved, the most important thing to keep in mind is the readability of the code. There are many possible cases here, such as depending on two different booleans, a complicated logical statement involving multiple comparisons, etc., so in general, use your best judgement to write code that is readable and consistent. If you are unsure whether guard or if is more readable or they seem equally readable, prefer using guard.
  • 3.11.3涉及展开可选项的情况下决定使用if语句还是guard语句时,要记住的最重要的事情是代码的可读性。 这里有很多可能的情况,比如依赖于两个不同的布尔值,一个复杂的逻辑语句涉及多重比较等等,所以一般来说,使用你最好的判断来编写可读且一致的代码。 如果您不确定 guardif 是否更具可读性,或者它们看起来同样可读,请首选使用 guard
// an `if` statement is readable here
if operationFailed {
    return
}

// a `guard` statement is readable here
guard isSuccessful else {
    return
}

// double negative logic like this can get hard to read - i.e. don't do this
guard !operationFailed else {
    return
}
  • 3.11.4 If choosing between two different states, it makes more sense to use an if statement as opposed to a guard statement.
  • 3.11.4 如果在两个不同的状态之间进行选择,使用 if 语句比使用 guard 语句更有意义。
// PREFERRED
if isFriendly {
    print("Hello, nice to meet you!")
} else {
    print("You have the manners of a beggar.")
}

// NOT PREFERRED
guard isFriendly else {
    print("You have the manners of a beggar.")
    return
}

print("Hello, nice to meet you!")
  • 3.11.5 You should also use guard only if a failure should result in exiting the current context. Below is an example in which it makes more sense to use two if statements instead of using two guards - we have two unrelated conditions that should not block one another.
  • 3.11.5 仅当失败导致退出当前上下文时,您才可以使用guard。 下面是一个示例,这里使用两个 if 语句而不应该使用两个 guard 语句——这里是两个不应该相互阻塞的不相关条件。
if let monkeyIsland = monkeyIsland {
    bookVacation(onIsland: monkeyIsland)
}

if let woodchuck = woodchuck, canChuckWood(woodchuck) {
    woodchuck.chuckWood()
}
  • 3.11.6 Often, we can run into a situation in which we need to unwrap multiple optionals using guard statements. In general, combine unwraps into a single guard statement if handling the failure of each unwrap is identical (e.g. just a return, break, continue, throw, or some other @noescape).
  • 3.11.6 通常,我们会遇到需要使用 guard 语句解开多个可选项的情况。 通常,如果处理每个解包的失败是相同的(例如,只是一个 returnbreakcontinuethrow 或其他一些 @noescape),则将多个解包语句合并为一个 guard 语句。
// combined because we just return
guard let thingOne = thingOne,
    let thingTwo = thingTwo,
    let thingThree = thingThree else {
    return
}

// separate statements because we handle a specific error in each case
guard let thingOne = thingOne else {
    throw Error(message: "Unwrapping thingOne failed.")
}

guard let thingTwo = thingTwo else {
    throw Error(message: "Unwrapping thingTwo failed.")
}

guard let thingThree = thingThree else {
    throw Error(message: "Unwrapping thingThree failed.")
}
  • 3.11.7 Don’t use one-liners for guard statements.
  • 3.11.7 不要在 guard 语句中使用单行。
// PREFERRED
guard let thingOne = thingOne else {
    return
}

// NOT PREFERRED
guard let thingOne = thingOne else { return }

4. Documentation/Comments

4.1 Documentation

If a function is more complicated than a simple O(1) operation, you should generally consider adding a doc comment for the function since there could be some information that the method signature does not make immediately obvious. If there are any quirks to the way that something was implemented, whether technically interesting, tricky, not obvious, etc., this should be documented. Documentation should be added for complex classes/structs/enums/protocols and properties. All public functions/classes/properties/constants/structs/enums/protocols/etc. should be documented as well (provided, again, that their signature/name does not make their meaning/functionality immediately obvious).
如果函数比简单的 O(1) 操作更复杂,您通常应该考虑为函数添加 doc 注释,因为可能存在一些方法签名(方法名和参数列表)并不是那么一目了然。 如果某些方法的实现方式有任何不易理解的代码,都应该记录下来。 应该为复杂的类/结构/枚举/协议和属性添加文档。 所有public函数/类/属性/常量/结构/枚举/协议/等。 也应该记录在案(同样前提是它们的签名/名称不能使功能一目了然)。

After writing a doc comment, you should option click the function/property/class/etc. to make sure that everything is formatted correctly.
编写文档注释后,您应该选择单击函数/属性/类/等,以确保所有内容格式正确。

Be sure to check out the full set of features available in Swift's comment markup described in Apple's Documentation.
请务必查看 Swift 注释标记中可用的全套功能Apple 文档中的描述

Guidelines:
准则:

  • 4.1.1 160 character column limit (like the rest of the code).

  • 4.1.1 160 个字符的列限制(与代码的其余部分一样)。

  • 4.1.2 Even if the doc comment takes up one line, use block (/** */).

  • 4.1.2 即使文档注释占一行,也要使用block (/** */)。

  • 4.1.3 Do not prefix each additional line with a *.

  • 4.1.3 不要在每个附加行前加上 *

  • 4.1.4 Use the new - parameter syntax as opposed to the old :param: syntax (make sure to use lower case parameter and not Parameter). Option-click on a method you wrote to make sure the quick help looks correct.

  • 4.1.4 使用新的 - parameter 语法而不是旧的 :param: 语法(确保使用小写的 parameter 而不是 Parameter)。 按住 Option 键单击您编写的方法以确保快速帮助看起来正确。

class Human {
    /**
     This method feeds a certain food to a person.

     - parameter food: The food you want to be eaten.
     - parameter person: The person who should eat the food.
     - returns: True if the food was eaten by the person; false otherwise.
    */
    func feed(_ food: Food, to person: Human) -> Bool {
        // ...
    }
}
  • 4.1.5 If you’re going to be documenting the parameters/returns/throws of a method, document all of them, even if some of the documentation ends up being somewhat repetitive (this is preferable to having the documentation look incomplete). Sometimes, if only a single parameter warrants documentation, it might be better to just mention it in the description instead.

  • 4.1.5 如果您要记录方法的参数/返回/抛出异常,请记录所有这些,即使某些文档最终有些啰嗦(这比不完整的文档更好)。有时,如果只有一个参数需要记录,最好在描述中提及它。

  • 4.1.6 For complicated classes, describe the usage of the class with some potential examples as seems appropriate. Remember that markdown syntax is valid in Swift's comment docs. Newlines, lists, etc. are therefore appropriate.

  • 4.1.6 对于复杂的类,用一些看起来合适的潜在例子来描述类的用法。 请记住 Markdown 语法在 Swift 的注释文档中是有效的。 因此,换行符、列表等是合适的。

/**
 ## Feature Support

 This class does some awesome things. It supports:

 - Feature 1
 - Feature 2
 - Feature 3

 ## Examples

 Here is an example use case indented by four spaces because that indicates a
 code block:

     let myAwesomeThing = MyAwesomeClass()
     myAwesomeThing.makeMoney()

 ## Warnings

 There are some things you should be careful of:

 1. Thing one
 2. Thing two
 3. Thing three
 */
class MyAwesomeClass {
    /* ... */
}
  • 4.1.7 When mentioning code, use code ticks - `
/**
 This does something with a `UIViewController`, perchance.
 - warning: Make sure that `someValue` is `true` before running this function.
 */
func myFunction() {
    /* ... */
}
  • 4.1.8 When writing doc comments, prefer brevity where possible.
  • 4.1.8 在编写文档注释时,尽可能简洁。

4.2 Other Commenting Guidelines

4.2 其他注释指南

  • 4.2.1 Always leave a space after //.

  • 4.2.1 始终在//后面加上一个空格.

  • 4.2.2 Always leave comments on their own line.

  • 4.2.2 注释必须另起一行。

  • 4.2.3 When using // MARK: - whatever, leave a newline after the comment.

  • 4.2.3 使用// MARK: - whatever时,在注释后换行。

class Pirate {

    // MARK: - instance properties

    private let pirateName: String

    // MARK: - initialization

    init() {
        /* ... */
    }

}

原文链接

Swift Style Guide

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

推荐阅读更多精彩内容

  • 注:以下皆为翻译,如有错误或疏漏,请指正。谢谢☺ 简介 (raywenderlich 版)您看到的这份规范可能与其...
    LovelyYilia阅读 4,361评论 1 17
  • Swift 编码规范 A guide to our Swift style and conventions. 按大...
    Suneday阅读 755评论 0 0
  • 从其他地方整理了一些编码规范的资料,分享给大家。YoY 这我们的首要目标是简洁,可读性和简单性。 1.命名(Nam...
    大脸猫121阅读 1,055评论 2 2
  • 注:以下皆为翻译,如有错误或疏漏,请指正。谢谢☺ 简介 SlideShare 版 Swift 官方 SlideSh...
    LovelyYilia阅读 844评论 0 4
  • A guide to our Swift style and conventions. This is an at...
    lxyz22zp阅读 888评论 0 1