首先推薦閱讀下 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() { /* ... */ } }