Swift 代码规范中文-Swift Style Guide

2021-11-26  本文已影响0人  Aaron升

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

目录

1. Code Formatting

1. 代码格式

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

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

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

class SomeClass {
    func someMethod() {
        if x == y {
            /* ... */
        } else if x == z {
            /* ... */
        } else {
            /* ... */
        }
    }

    /* ... */
}
// 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 {
    /* ... */
}
let myArray = [1, 2, 3, 4, 5]
let myValue = 20 + (30 / 2) * 3
if 1 + 1 == 3 {
    fatalError("The universe is broken.")
}
func pancake(with syrup: Syrup) -> Pancake {
    /* ... */
}
// 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!")
}
someFunctionWithManyArguments(
    firstArgument: "Hello, I am a string",
    secondArgument: resultFromSomeFunction(),
    thirdArgument: someOtherLocalProperty)

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

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

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

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

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)
    })
// 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. 命名

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

// "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 {
    /* ... */
}
// 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中不推荐这种写法。

class SomeClass<Model> { /* ... */ }
protocol Modelable {
    associatedtype Model
}
protocol Sequence {
    associatedtype IteratorType: Iterator
}
// PREFERRED
class RoundAnimatingButton: UIButton { /* ... */ }

// NOT PREFERRED
class CustomButton: UIButton { /* ... */ }
// 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
    }
}
// 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!
}

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

// 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 概述

// 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)
    }
}
// 推荐
let url = "xxx"
let port = 8080

// 不推荐
let url: String = "xxx"
let port: Int = 8080
func pirateName() -> (firstName: String, lastName: String) {
    return ("Guybrush", "Threepwood")
}

let name = pirateName()
let firstName = name.firstName
let lastName = name.lastName
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

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

// NOT PREFERRED
if (x == y) {
    /* ... */
}
// PREFERRED
imageView.setImageWithURL(url, type: .person)

// NOT PREFERRED
imageView.setImageWithURL(url, type: AsyncImageView.Type.person)
// PREFERRED
imageView.backgroundColor = UIColor.white

// NOT PREFERRED
imageView.backgroundColor = .white

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

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

do {
    let fileContents = try readFile("filename.txt")
} catch {
    print(error)
}

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

// 推荐
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 访问修饰符

// PREFERRED
private static let myPrivateNumber: Int

// NOT PREFERRED
static private let myPrivateNumber: Int
// PREFERRED
open class Pirate {
    /* ... */
}

// NOT PREFERRED
open
class Pirate {
    /* ... */
}
/**
 This property defines the pirate's name.
 - warning: Not `private` for `@testable`.
 */
let pirateName = "LeChuck"

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

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).")
    }
}
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 可选

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

// NOT PREFERRED
if let _ = someOptional {
    // do something
}
// PREFERRED
weak var parentViewController: UIViewController?

// NOT PREFERRED
weak var parentViewController: UIViewController!
unowned var parentViewController: UIViewController
guard let myValue = myValue else {
    return
}
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 属性

var computedProperty: String {
    if someBool {
        return "I'm a mighty pirate!"
    }
    return "I'm selling these fine leather jackets."
}
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
    }
}
class PirateManager {
    static let shared = PirateManager()

    /* ... */
}

3.8 Closures

3.8 闭包

// 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) }

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

let completionBlock: (Bool) -> Void = { (success) in
    print("Success? \(success)")
}

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

let completionBlock: (() -> Void)? = nil
// 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 数组

译者注:这点我自己做的不好,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 语句

// 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)
    }
}
// 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!)
// 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
}
// 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!")
if let monkeyIsland = monkeyIsland {
    bookVacation(onIsland: monkeyIsland)
}

if let woodchuck = woodchuck, canChuckWood(woodchuck) {
    woodchuck.chuckWood()
}
// 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.")
}
// 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:
准则:

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 {
        // ...
    }
}
/**
 ## 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 {
    /* ... */
}
/**
 This does something with a `UIViewController`, perchance.
 - warning: Make sure that `someValue` is `true` before running this function.
 */
func myFunction() {
    /* ... */
}

4.2 Other Commenting Guidelines

4.2 其他注释指南

class Pirate {

    // MARK: - instance properties

    private let pirateName: String

    // MARK: - initialization

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

}

原文链接

Swift Style Guide

上一篇下一篇

猜你喜欢

热点阅读