首先推荐阅读下 Apple's API Design Guidelines。ios
1. Code Formattinggithub
2. Namingswift
1.1 使用4个空格来代替Tabs
1.2 避免过长的行,能够在XCode中进行设置单行最大长度:(Xcode->Preferences->Text Editing->Page guide at column: 160 is helpful for this)
1.3 保证每一个文件结尾都存在一个新行 Ensure that there is a newline at the end of every file.
1.4 避免无心义的尾随空格: (Xcode->Preferences->Text Editing->Automatically trim trailing whitespace + Including whitespace-only lines).
1.5 避免将单独的左花括号放置到一行,咱们参考了:1TBS style.
class SomeClass { func someMethod() { if x == y { /* ... */ } else if x == z { /* ... */ } else { /* ... */ } } /* ... */ }
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 where T.RelatedType == U>(firstArgument: U, secondArgument: T) { /* ... */ } // calling a function someFunction(someArgument: "Kitten") // superclasses class PirateViewController: UIViewController { /* ... */ } // protocols extension PirateViewController: UITableViewDataSource { /* ... */ }
1.7 通常来讲,逗号后面都要跟随一个空格。
let myArray = [1, 2, 3, 4, 5]
1.8 在二元操做符譬如+
, ==
, 或者 ->
的先后须要加上空格,可是对于(
、`)的先后不须要加空格。
let myValue = 20 + (30 / 2) * 3 if 1 + 1 == 3 { fatalError("The universe is broken.") } func pancake() -> Pancake { /* ... */ }
1.9 咱们默认使用Xcode推荐的格式化风格(CTRL-I) ,在声明某个函数的时候会多行排布参数。
// 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 myFirstVariable > (mySecondVariable + myThirdVariable) && myFourthVariable == .SomeEnumValue { // Xcode indents to here for this kind of statement print("Hello, World!") }
1.10 在调用多参数函数的时候,会把多个参数放置到单独的行中:
someFunctionWithManyArguments( firstArgument: "Hello, I am a string", secondArgument: resultFromSomeFunction() thirdArgument: someOtherLocalVariable)
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 尽量地使用本地变量的方式来避免多行的判断语句。
// 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.1 Swift中不须要再使用Objective-C那样的前缀,譬如使用 GuybrushThreepwood
而不是LIGuybrushThreepwood
。
2.2 对于类型名即struct
, enum
, class
, typedef
, associatedtype
等等使用 PascalCase
。
2.3 对于函数名、方法名、变量名、常量、参数名等使用camelCase
。
2.4 在使用首字母缩写的时候尽量地所有大写,而且注意保证所有代码中的统一。不过若是缩写被用于命名的起始,那么就所有小写。
// "HTML" is at the start of a variable 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 对于静态常量使用 k
前缀 + PascalCase。
class MyClassName { // use `k` prefix for constant primitives static let kSomeConstantHeight: CGFloat = 80.0 // use `k` prefix for non-primitives as well static let kDeleteButtonColor = UIColor.redColor() // don't use `k` prefix for singletons static let sharedInstance = MyClassName() /* ... */ }
2.6 对于泛型或者关联类型,使用PascalCase
描述泛型,若是泛型名与其余重复,那么能够添加一个Type
后缀名到泛型名上。
class SomeClass<T> { /* ... */ } class SomeClass<Model> { /* ... */ } protocol Modelable { associatedtype Model } protocol Sequence { associatedtype IteratorType: Iterator }
2.7 命名必需要是不模糊的而且方便表述的
// PREFERRED class RoundAnimatingButton: UIButton { /* ... */ } // NOT PREFERRED class CustomButton: UIButton { /* ... */ }
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 对于不是很明显的类型须要将类型信息包含在属性名中。
// PREFERRED class ConnectionTableViewCell: UITableViewCell { let personImageView: UIImageView let animationDuration: NSTimeInterval // 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 // variable 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: NSTimeInterval // 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 variable // 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 // variable name and not at the start @IBOutlet weak var btnSubmit: UIButton! @IBOutlet weak var buttonSubmit: UIButton! // we should always have a type in the variable name when dealing with outlets // for example, here, we should have `firstNameLabel` instead @IBOutlet weak var firstName: UILabel! }
2.10 在编写函数参数的时候,要保证每一个参数都易于理解其功能。
2.11 根据 Apple's API Design Guidelines, 对于protocol
,若是其描述的是正在作的事情,譬如Collection
,那么应该命名为名词。而若是是用于描述某种能力,譬如Equatable
, ProgressReporting
,那么应该添加 able
, ible
, 或者 ing
这样的后缀。若是你的协议并不符合上述两种情形,那么应该直接添加一个Protocol
后缀,譬如:
// here, the name is a noun that describes what the protocol does protocol TableViewSectionProvider { func rowHeight(atRow 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.1.1 尽量地使用let
来代替var
。
3.1.2 尽量地使用 map
, filter
, reduce
的组合来进行集合的转换等操做,而且尽量地避免使用带有反作用的闭包。
// 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(integer) } }
3.1.3 尽量地显式声明不方便进行类型推测的变量或者常量的类型名。
3.1.4 若是你的函数须要返回多个参数,那么尽量地使用Tuple
来代替inout
参数。若是你会屡次使用某个元组,那么应该使用typealias
设置别名。若是返回的参数超过三个,那么应该使用结构体或者类来替代。
func pirateName() -> (firstName: String, lastName: String) { return ("Guybrush", "Threepwood") } let name = pirateName() let firstName = name.firstName let lastName = name.lastName
3.1.5 在建立delegates/protocols的时候须要当心所谓的保留环(retain cycles),这些属性须要被声明为weak
。
3.1.6 在闭包中直接调用self
可能会致使保留环,可使用capture list 在这种状况下:
myFunctionWithClosure() { [weak self] (error) -> Void in // you can do this self?.doSomething() // or you can do this guard let strongSelf = self else { return } strongSelf.doSomething() }
3.1.7 不要使用 labeled breaks。
3.1.8 不要在控制流逻辑判断的时候加上圆括号
// PREFERRED if x == y { /* ... */ } // NOT PREFERRED if (x == y) { /* ... */ }
3.1.9 避免在使用enum的时候写出全名
// PREFERRED imageView.setImageWithURL(url, type: .person) // NOT PREFERRED imageView.setImageWithURL(url, type: AsyncImageView.Type.person)
3.1.10 在写类方法的时候不能用简短写法,应该使用类名.方法名,这样可以保证代码的可读性
// PREFERRED imageView.backgroundColor = UIColor.whiteColor() // NOT PREFERRED imageView.backgroundColor = .whiteColor()
3.1.11 在非必要的时候不要写self.
。
3.1.12 在编写某个方法的时候注意考虑下这个方法是否有可能被复写,若是不可能被复写那么应该使用final
修饰符。还要注意加上final以后也会致使没法在测试的时候进行复写,因此仍是须要综合考虑。通常而言,加上final
修饰符后会提升编译的效率,因此应该尽量地使用该修饰符。
3.1.13 在使用譬如else
, catch
等等相似的语句的时候,将关键字与花括号放在一行,一样遵循1TBS style规范,这边列出了常见的if
/else
以及 do
/catch
示范代码。
if someBoolean { // do something } else { // do something else } do { let fileContents = try readFile("filename.txt") } catch { print(error) }
3.2.1 在须要的时候应该将访问修饰符放在关键字的第一位。
// PREFERRED private static let kMyPrivateNumber: Int // NOT PREFERRED static private let kMyPrivateNumber: Int
3.2.2 访问修饰符不该该单独放一行:
// PREFERRED public class Pirate { /* ... */ } // NOT PREFERRED public class Pirate { /* ... */ }
3.2.3 通常来讲,不要显式地写默认的 internal
访问修饰符。
3.2.4 若是某个变量须要在测试的时候被使用到,那么应该标识为internal
来保证@testable import ModuleName
。这里须要注意的是,对于某些应该被声明为private
的变量由于测试用途而声明为了internal
,那么应该在注释里特别地注明。
/** This variable defines the pirate's name. - warning: Not `private` for `@testable`. */ let pirateName = "LeChuck"
尽量地选用命名函数来代替自定义操做符。若是你打算引入一个自定义的操做符,那么必定要有很是充分的理由来讲明为啥要讲一个新的操做符引入到全局做用域,而不是使用其余一些可替代的方式。你也能够选择去复写一些现有的操做符,譬如==
来适应一些新的类型,不过要保证你添加的用法必定要与语义相符。譬如==
应该只能用于表示相等性测试而且返回一个布尔值。
enum
s3.4.1 在使用枚举类型做为switch的参数的时候,避免引入default
关键字,而应该将没有使用的情形放到下面而后使用break关键字来避免被执行。
3.4.2 Swift中默认会在每一个case的结尾进行break,所以不必的时候不须要显式地声明break
关键字。
3.4.3 The case
statements should line up with the switch
statement itself as per default Swift standards.
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)
).
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 优先使用譬如case 1, 2, 3:
这样的列表表达式而不是使用fallthrough
关键字。
3.4.6 若是你添加了一个默认的case而且该case不该该被使用,那么应该在default情形下抛出异常。
func handleDigit(digit: Int) throws { 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.1 只应该在 @IBOutlet
中使用隐式地未包裹的Options。不然其余状况下就应该使用Non-Optional或者正常的Optional的变量。虽然有时候你能保证某个变量确定非nil
,不过这样用的话仍是比较安全而且能保证上下一致性。
The only time you should be using implicitly unwrapped optionals is withs. In every other case, it is better to use a non-optional or regular optional variable. Yes, there are cases in which you can probably "guarantee" that the variable will never be nil
when used, but it is better to be safe and consistent.
3.5.2 不要使用 as!
或者 try!
.
3.5.3 若是你只是打算判断存放在Optional中的值是否为空,那么你应该直接与nil
进行判断而不是使用if let
语句将值取出来。
// PREFERERED if someOptional != nil { // do something } // NOT PREFERRED if let _ = someOptional { // do something }
3.5.4 不要使用 unowned
。你能够将unowned
当作对于weak
变量的隐式解包,虽然有时候unowned
与weak
相比有小小地性能提高,不过仍是不建议进行使用。
// PREFERRED weak var parentViewController: UIViewController? // NOT PREFERRED weak var parentViewController: UIViewController! unowned var parentViewController: UIViewController
3.5.5 当对Optionals进行解包的时候,使用与Optionals变量一致的变量名
guard let myVariable = myVariable else { return }
在实现协议的时候,大致上有两种代码组织方式:
使用 // MARK:
来注释你的专门用于实现协议中规定的方法
在你的类或者结构体实现以外使用一个扩展来存放实现代码,不过要保证在一个源文件中
不过须要注意的是,若是你是使用了Extension方式,那么定义在Extension中的方法是没法被子类复写的,这样可能会没法进行测试。
3.7.1 若是是定义一个只读的须要通过计算的属性,那么不须要声明 get {}
var computedProperty: String { if someBool { return "I'm a mighty pirate!" } return "I'm selling these fine leather jackets." }
3.7.2 在使用 get {}
, set {}
, willSet
, 以及 didSet
, 注意块的缩进
3.7.3 尽管你能够在willSet
/didSet
以及 set
方法中使用自定义的名称,不过建议仍是使用默认的newValue
/oldValue
变量名
var computedProperty: String { get { if someBool { return "I'm a mighty pirate!" } return "I'm selling these fine leather jackets." } set { computedProperty = newValue } willSet { print("will set to \(newValue)") } didSet { print("did set from \(oldValue) to \(newValue)") } }
3.7.4 将任何类常量设置为static
class MyTableViewCell: UITableViewCell { static let kReuseIdentifier = String(MyTableViewCell) static let kCellHeight: CGFloat = 80.0 }
3.7.5 可使用以下方式便捷地声明一个单例变量:
class PirateManager { static let sharedInstance = PirateManager() /* ... */ }
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 在参数列表中,若是是使用了捕获变量或者声明了非Void的返回值,那么应该将参数列表写在一个圆括号里,其余状况下则能够省略圆括号。
// parentheses due to capture list doSomethingWithClosure() { [weak self] (response: NSURLResponse) in self?.handleResponse(response) } // parentheses due to return type doSomethingWithClosure() { (response: NSURLResponse) -> String in return String(response) }
3.8.3 若是你是将闭包声明为一个类型,那么除非该类型为Optional或者该闭包是另外一个闭包的参数,不然不须要使用圆括号进行包裹。不过须要用圆括号来标注参数列表,而且使用Void
来指明没有任何结果返回。
let completionBlock: (success: Bool) -> Void = { print("Success? \(success)") } let completionBlock: () -> Void = { print("Completed!") } let completionBlock: (() -> Void)? = nil
3.8.4 尽量地将参数名与左括号放在一行,不过要避免打破每行最长160个字符的限制。
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.5 尽量地使用 trailing closure表达式,除非须要显示地声明闭包参数的外部参数名。
// 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)") })
3.9.1 通常来讲,避免使用下标直接访问某个数组,而应该使用相似于.first
、.last
这样的访问器进行访问。另外,应该优先使用for item in items
语法来替代for i in 0..<items.count
。若是你打算用下标遍历数组,那么必定保证不能越界。
3.9.2 永远不要使用+=
或者 +
运算符来增长或者链接数组,应该使用.append()
或者 .appendContentsOf()
方法。若是你想定义一个从其余数组生成的不可变数组,那么应该使用let
关键字,即: let myNewArray = arr1 + arr2
, 或者 let myNewArray = [arr1, arr2].flatten()
。
假设某个函数 myFunction
须要去返回一个String
类型,不过有可能会在某个点抛出异常,通常来讲会将该函数的返回值设置为String?
:
Example:
func readFile(withFilename filename: String) -> String? { guard let file = openFile(filename) else { return nil } let fileContents = file.read() file.close() return fileContents } func printSomeFile() { let filename = "somefile.txt" guard let fileContents = readFile(filename) else { print("Unable to open file \(filename).") return } print(fileContents) }
不过做为异常处理的角度,咱们应该使用Swift的try-catch
表达式,这样能显式地知道错误点:
struct Error: ErrorType { 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(withFilename filename: String) throws -> String { guard let file = openFile(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(filename) print(fileContents) } catch { print(error) } }
总而言之,若是某个函数可能会出错,而且出错的缘由不能显式地观测到,那么应该优先抛出异常而不是使用一个Optional做为返回值。
guard
Statements3.11.1 通常来讲,咱们会优先使用所谓的"early return"策略来避免if
表达式中的多层嵌套的代码。在这种状况下使用guard
语句可以有效地提高代码的可读性。
// PREFERRED func eatDoughnut(atIndex index: Int) { guard index >= 0 && index < doughnuts else { // return early because the index is out of bounds return } let doughnut = doughnuts[index] eat(doughnut) } // NOT PREFERRED func eatDoughnuts(atIndex index: Int) { if index >= 0 && index < donuts.count { let doughnut = doughnuts[index] eat(doughnut) } }
3.11.2 在对Optional类型进行解包的时候,优先使用 guard
语句来避免if
语句中较多的缩进。
// PREFERRED guard let monkeyIsland = monkeyIsland else { return } bookVacation(onIsland: monkeyIsland) bragAboutVacation(onIsland: monkeyIsland) // NOT PREFERRED if let monkeyIsland = monkeyIsland { bookVacation(onIsland: monkeyIsland) bragAboutVacation(onIsland: monkeyIsland) } // EVEN LESS PREFERRED if monkeyIsland == nil { return } bookVacation(onIsland: monkeyIsland!) bragAboutVacation(onIsland: monkeyIsland!)
3.11.3 在决定是要用if
表达式仍是guard
表达式进行Optional类型解包的时候,最重要的点就是要保证代码的可读性。不少时候要注意因时而变,因地制宜:
// 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
表达式而不是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 通常来讲,guard
应该被用于须要直接退出当前上下文的情形。而对于下面这种两个条件互不干扰的状况,应该使用两个if
而不是两个guard
。
if let monkeyIsland = monkeyIsland { bookVacation(onIsland: monkeyIsland) } if let woodchuck = woodchuck where canChuckWood(woodchuck) { woodchuck.chuckWood() }
3.11.6 有时候咱们会碰到要用guard
语句进行多个optionals解包的状况,通常而言,对于复杂的错误处理的Optional类型须要将其拆分到多个单个表达式中。
// 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 不要将guard
表达式强行缩写到一行内。
// PREFERRED guard let thingOne = thingOne else { return } // NOT PREFERRED guard let thingOne = thingOne else { return }
若是某个函数不是简单地O(1)
操做,那么最好就是为该函数添加一些注释文档,这样能有效地提升代码的可读性与可维护性。以前有个很是不错的文档工具VVDocumenter。推荐阅读Apple的官方指南中的描述:described in Apple's Documentation.
Guidelines:
4.1.1 每行不该超过160个字符
4.1.2 即便某些注释只有一行,也应该使用块注释符: (/** */
).
4.1.3 不用给每行的开头都加上: *
.
4.1.4 使用新的 - parameter
标识符来代替老的:param:
syntax (注意这边是小写的 parameter
而不是Parameter
).
4.1.5 若是你准备对参数/返回值/异常值来写注释,那么注意要一个不落的全局加上,尽管有时候会让文档显得重复冗余。有时候,若是只须要对单个参数进行注释,那么还不如直接放在描述里进行声明,而不须要专门的为参数写一个注释。
4.1.6 对于复杂的使用类,应该添加一些具体的使用用例来描述类的用法。注意Swift的注释文档中是支持MarkDown语法的,这是一个很好的特性。
/** ## 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 使用 - ` 在注释中著名引用的代码
/** This does something with a `UIViewController`, perchance. - warning: Make sure that `someValue` is `true` before running this function. */ func myFunction() { /* ... */ }
4.1.8 保证文档的注释尽量的简洁
4.2.1 //
后面老是要跟上一个空格
4.2.2 注释永远要放在单独的行中
4.2.3 在使用// MARK: - whatever
的时候,注意MARK与代码之间保留一个空行
class Pirate { // MARK: - instance properties private let pirateName: String // MARK: - initialization init() { /* ... */ } }