1. 程式人生 > >Swift Style Guide

Swift Style Guide

Specifics from these guidelines + additional remarks are mentioned below.

This guide was last updated for Swift 2.2 on August 17th, 2016.

Table Of Contents

1. Code Formatting

  • 1.1 Use 4 spaces for tabs.
  • 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.3 Ensure that there is a newline at the end of every file.
  • 1.4 Ensure that there is no trailing whitespace anywhere (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
    .
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.
// 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 In general, there should be a space following a comma.
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 ).
let myValue = 20 + (30 / 2) * 3
if 1 + 1 == 3 {
    fatalError("The universe is broken.")
}
func pancake() -> 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.
// 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.
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.
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.
// 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.1 There is no need for Objective-C style prefixing in Swift (e.g. use just GuybrushThreepwood instead of LIGuybrushThreepwood).

  • 2.2 Use PascalCase for type names (e.g. structenumclasstypedefassociatedtype, etc.).

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

  • 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.

// "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 Use k prefix + PascalCase for naming all static constants that are not singletons.
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 For generics and associated types, use either a single capital letter or 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.
class SomeClass<T> { /* ... */ }
class SomeClass<Model> { /* ... */ }
protocol Modelable {
    associatedtype Model
}
protocol Sequence {
    associatedtype IteratorType: Iterator
}
  • 2.7 Names should be descriptive and unambiguous.
// PREFERRED
class RoundAnimatingButton: UIButton { /* ... */ }

// NOT PREFERRED
class CustomButton: UIButton { /* ... */ }
  • 2.8 Do not abbreviate, use shortened names, or single letter names.
// 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.
// 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
    // 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: 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 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.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 ableible, or ing if it describes a capability (e.g. EquatableProgressReporting). 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.

// 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. Coding Style

3.1 General

  • 3.1.1 Prefer let to var whenever possible.

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

// 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.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 classinstead.

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.6 Be careful when calling self directly from a closure as this can cause a retain cycle - use a capture list when this might be the case:

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 Don't use labeled breaks.

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

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

// NOT PREFERRED
if (x == y) {
    /* ... */
}
  • 3.1.9 Avoid writing out an enum type where possible - use shorthand.
// 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.
// PREFERRED
imageView.backgroundColor = UIColor.whiteColor()

// NOT PREFERRED
imageView.backgroundColor = .whiteColor()
  • 3.1.11 Prefer not writing self. unless it is required.

  • 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-finalin a library as opposed to have changing something to be non-final in your local project.

  • 3.1.13 When using a statement such as elsecatch, 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.

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

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

3.2 Access Modifiers

  • 3.2.1 Write the access modifier keyword first if it is needed.
// PREFERRED
private static let kMyPrivateNumber: Int

// NOT PREFERRED
static private let kMyPrivateNumber: Int
  • 3.2.2 The access modifier keyword should not be on a line by itself - keep it inline with what it is describing.
// PREFERRED
public class Pirate {
    /* ... */
}

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

  • 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.

/**
 This property defines the pirate's name.
 - warning: Not `private` for `@testable`.
 */
let pirateName = "LeChuck"

3.3 Custom Operators

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.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.2 Since switch cases in Swift break by default, do not include the break keyword if it is not needed.

  • 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 Prefer lists of possibilities (e.g. case 1, 2, 3:) to using the fallthrough keyword where possible).

  • 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).

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 Optionals

  • 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.

  • 3.5.2 Don't use as! or 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.

// PREFERERED
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.
// 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.
guard let myValue = myValue else {
    return
}

3.6 Protocols

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

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.

3.7 Properties

  • 3.7.1 If making a read-only, computed property, provide the getter without the get {} around it.
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.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.
            
           

相關推薦

Swift Style Guide

Specifics from these guidelines + additional remarks are mentioned below. This guide was last updated for Swift 2.2 on August 17th, 2016. Table Of Conte

Google C++ style guide——格式

空白 ont long 註意 part 字符串常量 requires () ace 1.行長度 每一行代碼字符數不超過80。 例外: 1)假設一行凝視包括了超過80字符的命令或URL,出於復制粘貼的方便能夠超過80字符; 2)包括長路徑的能夠超出80列,盡量避免; 3)

Shell Style Guide

align array arr logical round email mac practice opp Shell Style Guide Revision 1.26 Paul ArmstrongToo many more to mention Each style p

一張圖總結Google C++程式設計規範(Google C++ Style Guide)【轉】

(轉自:https://blog.csdn.net/voidccc/article/details/37599203?utm_source=blogxgwz0) Google C++ Style Guide是一份不錯的C++編碼指南,我製作了一張比較全面的說明圖,可以在短時間內快速掌握規範的重點

iOS Coding Style Guide 程式碼規範

前言 程式碼規範可以說是老生常談的話題了, 也是程式設計師自我修養的一種體現, 雖然一套好的程式碼規範不能使程式執行的更加流暢, 不能使程式直接的影響到程式的功能執行,但是如果能再發開之前就能明確定義一套程式碼規範,並且嚴格的去執行,肯定能非常有效的提高程式碼閱讀性,高的閱讀性也使得後期開發,維

Google C++Style Guide【C++程式設計風格指南解讀】——命名約定

       最重要的一致性規則是命名管理. 命名風格快速獲知名字代表是什麼東東: 型別? 變數? 函式? 常量? 巨集 ... ? 甚至不需要去查詢型別宣告. 我們大腦中的模式匹配引擎可以非常可靠的

The Yelp Production Engineering Documentation Style Guide

Documentation is something that many of us in software and site reliability engineering struggle with – even if we recognize its importance, it can

Google C++ Style Guide中英對照(三)

1 Naming 命名規則 The mostimportant consistency rules are those that govern naming. The style of a nameimmediately informs us what sort of th

命名約定--Google Style Guide

最重要的一致性規則是命名管理. 命名的風格能讓我們在不需要去查詢型別宣告的條件下快速地瞭解某個名字代表的含義: 型別, 變數, 函式, 常量, 巨集, 等等, 甚至. 我們大腦中的模式匹配引擎非常依賴這些命名規則. 命名規則具有一定隨意性, 但相比按個人喜好命名, 一致性更重要, 所以無

Google C++ Style Guide

這裡包括了大多數,但是末尾的關於函式呼叫等具體寫法,不好用一句話來總結,請參考原文; 重點的有爭議的已經粗體標出,具體原因可以參考原文; 通常每一個cpp檔案都應該關聯一個頭檔案,除非單元測試;所有

Google C++程式碼風格指南翻譯簡化版(google c++ code style guide)【七】

本文件基於網上流傳的Google C++程式設計風格指南,由 edisonpeng(2009/3/25)整理 本地化簡化由MISAS開發團隊使用。在此分享以供各開發團隊參考。 目錄 格式化 MISAS開發團隊的C++開發規範約定,1個T

本人精心製作的 Google C++ Style Guide pdf 版本

花了一些時間製作了著名的 Google C++ Style Guide 的PDF版本,有大標題的書籤,有目錄(可點選直達目標)。 (說明,本人不經常登部落格,有瑕疵了不能及時更正,請見諒) 這是一張截圖:

Google C++ Style Guide的哲學

Google C++ Style Guide並不是一個百科全書,也不是一個C++使用指南,但它描述適用於Google及其開源專案的編碼指南,並不追求全面和絕對正確,也有許多人置疑它的一些規則。但作為一個最具影響力的編碼規範,它裡面有許多內容值得我們研究學習。

一張圖總結Google C++程式設計規範(Google C++ Style Guide)

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

讀 Metal Programming Guide: Tutorial and Reference via Swift

市面上關於metal的專著極少,當然apple的文件永遠是最好、最新、最及時的參考,但是一本系統講解,有示例解析的書定然會幫助我們更快更好掌握這門新的技術。 metal,本身不是新技術,2014年在ios上第一次出現,之後逐漸支援macOS、watchOS、tvOS,現在i

swift中通知的使用

lin ont view selector load pan span 處的 ext ios討論群1群:135718460 1.發通知。(以這條通知為例,通知名字:gameOverNotification。通知參數:title) NSNotificationCent

外部樣式表聲明的樣式並不會進入style對象

樣式 http img 一個 16px col function cnblogs image 在網頁設計當中,我們註重網頁的行為(js)、結構(HTLM)、樣式(css)分離開 內聯樣式表或者內部樣式表聲明的樣式信息都會進入style對象。 我們可以測試一下: 但是我們的

Swift:閉包(Closures)

ins 總結 ole n) 而在 unsafe width content decode 一、 基本概念 閉包(Closures)是自包括的功能代碼塊,能夠在代碼中使用或者用來作為參數傳值。 在Swift中的閉包與C、OC中的blocks和其他編程語言(如C#)中的l

iOS開發項目實戰——Swift實現圖片輪播與瀏覽

0.10 上網 timer類 開發項目 cas hub string obj tle 近期開始開發一個新的iOS應用,自己決定使用Swift。進行了幾天之後,發現了一個非常嚴峻的問題。那就是無論是書籍,還是網絡資源,關於Swift的實在是太少了,隨便一

css reset style

height figure detail menu size sub ddr enter out /** * Eric Meyer‘s Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) * http://c