├── Swift_style_guide.jpg
├── LICENSE
├── BestPractices.md
└── README.md
/Swift_style_guide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prolificinteractive/swift-style-guide/HEAD/Swift_style_guide.jpg
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
--------------------------------------------------------------------------------
/BestPractices.md:
--------------------------------------------------------------------------------
1 | # Best Practices
2 |
3 | This is Prolific's Swift best practices document.
4 |
5 | The purpose of these best practices is to help you keep clean and bug free Swift code that is recommended to follow in your daily work.
6 |
7 | # Table Of Contents
8 |
9 | * [Nil Checking](#nil-checking)
10 | * [Assertion Management](#assertion-management)
11 | * [Property Observers](#property-observers)
12 | * [Retain Cycle](#retain-cycle)
13 | * [Documentation](#documentation)
14 | * [Access Control](#access-control)
15 |
16 | ## Nil Checking
17 |
18 | Though we have conventions for nil checking in the swift style guide, below are some suggestions for nil checking in certain situations.
19 |
20 | If there's a case where you want to enter a scope if AT LEAST ONE item is non-nil then use the `??` operator.
21 |
22 | ```swift
23 | if let _ = item ?? item1 {
24 | // At least one of these is not nil
25 | }
26 | ```
27 |
28 | If you want to check for non-nil AND evaluate a bool property or series of bool properties, use the `where` keyword.
29 |
30 | ```swift
31 | if let _ = item where propertyBoolOne && !propertyBoolTwo {
32 | // Bool properties have been evaluated.
33 | }
34 | ```
35 |
36 | If you want to enter a scope, only if an object is nil, then you can check directly for nil.
37 |
38 | ```swift
39 | if item == nil {
40 | // Do stuff..
41 | }
42 | ```
43 |
44 | ## Assertion management
45 |
46 | When working with optional values you have to make sure that the variable you work with doesn’t have a `nil` value. To do so you can use the different unwrapping techniques provided by the standard library, but in certain scenarios it can make sense to force unwrap your value and terminate your program (for example a wrong view controller type after instantiating from a Storyboard). In this case your app better terminate in order to avoid unexpected behaviors.
47 |
48 | The standard Swift library provides you different assertion functions that affect your code differently:
49 |
50 | * assert
51 | * assertionFailure
52 | * precondition
53 | * preconditionFailure
54 | * fataError
55 |
56 | ### assert
57 | `assert` is only evaluated in debug mode, it means that the line will be removed in release and will not be executed.
58 |
59 | ### assertionFailure
60 | `assertionFailure` acts like `assert` but provides some context to the compiler.
61 |
62 | ### precondition
63 | `precondition` ensures that the given condition is meet. If not the app will terminate. `precondition` works for both debug and release.
64 |
65 | ### preconditionFailure
66 | `preconditionFailure` means a fatal error and will terminate in both debug and release mode, except for unchecked builds (`-Ounchecked`), then it will never be executed.
67 |
68 | ### fatalError
69 | `fatalError` acts like `preconditionFailure` but is not affected by the unchecked build flag. It will always terminate your app in both debug and release mode.
70 |
71 | ### Production Builds
72 |
73 | While forcing a crash in debug builds is acceptable for testing purposes, it is not ideal to have the program exit on assertion failure in production builds. Instead, handling the error with a default value like `0` or empty array might be preferable. To do so, we recommend implementing a function that takes an optional value as well as a tuple containing the default value of the same type and a error message for the context.
74 |
75 | ```swift
76 | func nilOrDefault(value: T?, @autoclosure defaultValue: () -> (value: T, text: String)) -> T {
77 | assert(value != nil, defaultValue().text)
78 | return value ?? defaultValue().value
79 | }
80 |
81 | let integer = nilOrDefault(Int("s"), defaultValue: (value: 0, text: "Expected int not working"))
82 | // crash in Debug
83 | // 0 in Release
84 | ```
85 |
86 | You can also define a custom operator doing the same thing if you want a more concise syntax:
87 |
88 | ```swift
89 | infix operator ?! {}
90 |
91 | func ?!(wrapped: T?, @autoclosure nilDefault: () -> (value: T, text: String)) -> T {
92 | return nilOrDefault(wrapped, defaultValue: (value: value, text: text))
93 | }
94 |
95 | let integer = Int(string) ?! (0, “Expected integer, got \(string)”)
96 | // crash in Debug
97 | // 0 in Release
98 | ```
99 |
100 | ## Property Observers
101 | Cf Apple documentation:
102 |
103 | ```
104 | Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.
105 | ```
106 |
107 | You can use 2 types of property observer:
108 |
109 | * *willSet* is called just before the property value is stored.
110 | * *didSet* is called right after the property value is stored.
111 |
112 | ```swift
113 | var intValue: Int = 0 {
114 | willSet(newIntValue) {
115 | print("About to set intValue to \(newIntValue)")
116 | }
117 | didSet {
118 | print("Set intValue to \(intValue)")
119 | }
120 | }
121 | ```
122 |
123 | `didSet` is very useful when working with a data source array so you can automatically refresh the table view or collection view associated with the array.
124 |
125 | ```
126 | var dataSource: [String] {
127 | didSet {
128 | self.tableView.reloadData()
129 | }
130 | }
131 | ```
132 |
133 | Be careful to use *didSet* only on an initialized property. A typical example where it is dangerous to use *didSet* is to set an IBOutlet value before the view loaded.
134 |
135 | ```swift
136 | final class myViewController: UIViewController {
137 |
138 | @IBOutlet weak var label: UILabel!
139 |
140 | var text: String {
141 | didSet {
142 | self.label.text = text
143 | }
144 | }
145 |
146 | }
147 |
148 | let myViewController = UIViewController()
149 | myViewController.text = "Prolific" // Crash because the view controller label has not been initialized yet
150 | ```
151 |
152 | ## Retain Cycle
153 |
154 | To avoid retain cycle in Swift -- meaning when two objects both have strong references to each other -- use **weak** and **unowned** on your references to avoid having a strong reference on both sides.
155 |
156 | * A **weak** reference is a pointer to an object that **doesn't protect** the object from being deallocated by [ARC](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html). The object **can** be nil.
157 | * A **unowned** reference is a pointer to an object that **doesn't protect** the object from being deallocated by [ARC](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html). The object **can't** be nil.
158 |
159 | According to Apple's [documentation](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html):
160 |
161 | ```Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.```
162 |
163 | #### Example
164 |
165 | ```swift
166 | final class MyClass {
167 |
168 | let notNilInstance = Instance()
169 | weak var delegate: MyDelegate?
170 |
171 | func myFunction() {
172 | delegate?.doSomething()
173 | }
174 |
175 | func myFunctionWithClosure() {
176 | let closure = { [weak self, unowned notNilInstance] in
177 | self?.doSomething() // weak variables are optionals
178 | notNilInstance.doSomethingElse() // unowned variables are not
179 | }
180 |
181 | }
182 | ```
183 |
184 | #### Debug
185 |
186 | [Here](http://applifebalance.com/posts/retain-cycle-instruments/) is an article on how to diagnose retain cycle bugs in your app using Instruments. Another easy way is to print inside the `deinit` function of your objects and see if they get deallocated.
187 |
188 | #### Note
189 |
190 | Retain cycle doesn't apply to Swift structs since they are passed by value and not by reference.
191 |
192 | *Rationale* Retain cycle bugs are very easy to reproduce, being very careful when manipulating pointers is crucial to build a solid app.
193 |
194 | ## Documentation
195 |
196 | ### Format
197 |
198 | The documentation format should follow the markup format referenced by [Apple](https://developer.apple.com/library/mac/documentation/Xcode/Reference/xcode_markup_formatting_ref/).
199 |
200 | ### VVDocumenter
201 |
202 | [VVDocumenter](https://github.com/onevcat/VVDocumenter-Xcode) is an Xcode plugin that generates the documentation for you, and provides inline placeholders so you can fill everything easily.
203 |
204 | ### Shared Views
205 |
206 | If you are sharing a view across your app, it can be helpful to provide a screenshot of it in the documentation to have a quick visual feedback on the look of your view. To do so, you can use the markup format : ``
207 |
208 | ### References
209 |
210 | When you document some code that is coming from a tutorial or is referenced in a public document, you should provide the reference of it in your documentation. To do so you can use the `seealso` keyword from the Apple Markup Format.
211 |
212 | ```
213 | /**
214 | This is my documentation.
215 |
216 | - seealso: [The Prolific Swift Style Guide](https://github.com/prolificinteractive/swift-style-guide)
217 | */
218 | ```
219 |
220 | ### Annotations
221 |
222 | You can provide different annotations to inform other developers about the code they are looking at. Different keywords are available, such as `important` to highlight critical information, `note` to provide additional information, `warning` to warn other developers about this piece of code.
223 |
224 | ## Access Control
225 |
226 | ```
227 | private (most restrictive) -> fileprivate -> internal -> public -> open (least restrictive)
228 | ```
229 |
230 | Starting with Swift 3, Apple has introduced two new access levels, `open` and `fileprivate`, in addition to the existing three. When choosing access levels for types defined within your project, follow Apple's [recommendations](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AccessControl.html). For single-target apps, `internal` or a more restrictive access level should be used. For frameworks and code that need to be accessed from a different module, expose the public-facing interface using `public` or `open`. Implementation details such framework can and should still be hidden with the default access level of `internal`.
231 |
232 | Start with the most restrictive access level, `private`, and increase access as needed when defining member constants, variables or functions. If a type's member or function needs to be accessed from a protocol conformance extension within the same file as described in [this section](https://github.com/prolificinteractive/swift-style-guide#file-structure), use the access level of `fileprivate`.
233 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Table Of Contents
4 |
5 | * [Overview](#overview)
6 | * [Linter](#linter)
7 | * [Standards](#standards)
8 | * [Naming Conventions](#naming-conventions)
9 | * [File Structure](#file-structure)
10 | * [Types](#types-1)
11 | * [Statement Termination](#statement-termination)
12 | * [Variable Declaration](#variable-declaration)
13 | * [Self](#self)
14 | * [Structs & Classes](#structs--classes)
15 | * [Bracket Syntax](#bracket-syntax)
16 | * [Force Unwrap](#force-unwrap)
17 | * [Error Handling](#error-handling)
18 | * [Access Modifiers](#access-modifiers)
19 | * [Imports](#imports)
20 | * [Nil Checking](#nil-checking)
21 | * [Implicit Getters](#implicit-getters)
22 | * [Enums](#enums)
23 | * [Use of `final`](#use-of-final)
24 | * [Operators](#operators)
25 | * [Documentation](#documentation)
26 | * [Best Practices](BestPractices.md)
27 |
28 |
29 | # Overview
30 |
31 | This is Prolific's style guide for writing code in Swift. The purpose of this guide is to develop
32 | a universal standard for Swift code that makes our codebases consistent and easy to read. This guide aims for
33 | consistent and clean code written in Swift in line with Apple and the general community.
34 |
35 | The standards have been influenced by:
36 |
37 | * Apple's language design decisions -- specifically, its desire for Swift code to be written concisely and expressively
38 | * Xcode's defaults for code formatting
39 | * The general community
40 |
41 | ### Contributing
42 |
43 | If you wish to contribute, feel free to submit a pull request or file an issue on this repo. In the pull request, be sure to discuss what problem you are intending
44 | to solve and the rationale to do so. When submitting a pull request, consider:
45 |
46 | * Is my suggestion general enough to be considered a code standard for all code bases?
47 | * Does my suggestion fall in line with Apple's desire for the language?
48 | * Does your suggestion invalidate a language feature?
49 |
50 | Make sure to consider the resources in the open-source Swift repo; specifically, read through the various
51 | [proposals](https://github.com/apple/swift-evolution/tree/master/proposals) for new language features as well as the
52 | [most-commonly rejected proposals](https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md) in order to
53 | guide your design principals.
54 |
55 | # Linter
56 |
57 | In order to automate many of the rules here, we recommend using [our fork of Swiftlint](https://github.com/prolificinteractive/SwiftLint) in your Swift codebase.
58 | While the main fork of Swiftlint is based around the GitHub style guide for Swift, our fork has additional rules and corrections for rules specific to our
59 | style guide that you will not find in the GitHub one.
60 |
61 |
62 | # Standards
63 |
64 | ## Naming Conventions
65 |
66 | The Apple Swift [API design guidelines](https://swift.org/documentation/api-design-guidelines/) promote clarity over brevity. Code should be concise, readable and clear at the point of use. However, having compact code that sacrifices clarity is a non-goal.
67 |
68 | ### Types
69 |
70 | Write all type names with UpperCamelCase, function and variable names with lowerCamelCase.
71 |
72 | ```swift
73 | class MyClass { }
74 | protocol MyProtocol { }
75 | func myFunction() { }
76 | var myVariable: String
77 | ```
78 |
79 | Avoid acronyms and abbreviations for clarity and readability. If you have to use an acronym, use upper case.
80 |
81 | ```swift
82 | productURL = NSURL()
83 | userID = "12345"
84 | ```
85 |
86 | ### Protocols
87 |
88 | Protocol names describing something should be a noun: `Collection`, `Element`. Protocol names describing an ability should end with “ing” or “able”: `Evaluatable`, `Printable`, `Formatting`.
89 |
90 | ### Enums
91 |
92 | Enum cases start with lowerCamelCase.
93 |
94 | ```
95 | enum Color {
96 | case red
97 | case blue
98 | case green
99 | case lightBlue
100 | }
101 | ```
102 |
103 | ### Functions
104 |
105 | Name your function with words that describe its behavior. Here is an example with a function that removes an element at an index x.
106 |
107 | **Preferred:**
108 | ```swift
109 | func remove(at index: Index) -> Element
110 | ```
111 |
112 | **Not Preferred:**
113 | ```swift
114 | func remove(index: Index) -> Element
115 | ```
116 |
117 | *Rationale*: It is better to specify that we are removing the element at the given index, and we are not trying to remove the given parameter itself, to make the behavior of the function very clear.
118 |
119 | Avoid unnecessary words in the function name.
120 |
121 | **Preferred:**
122 | ```swift
123 | func remove(_ element: Element) -> Element?
124 | ```
125 |
126 | **Not Preferred:**
127 | ```swift
128 | func removeElement(_ element: Element) -> Element?
129 | ```
130 |
131 | *Rationale*: It makes the code clearer and more concise. Adding extra unnecessary words will make the code harder to read and understand.
132 |
133 | Name your functions based on their side effects and behaviors.
134 |
135 | * With side effects: use **imperative verb** phrases:
136 | * `print(x)`, `x.sort()`, `x.append(y)`
137 | * Without side effects: use **noun** phrases:
138 | * `x.formattedName()`, `x.successor()`
139 |
140 | When the function can be described by a verb, use an imperative verb for the mutating function and apply “ed” or “ing” to the nonmutating function:
141 | * Mutating function:
142 | * `x.sort()`
143 | * `x.append(y)`
144 | * Nonmutating function:
145 | * `z = x.sorted()`
146 | * `z = x.appending(y)`
147 |
148 | Name functions to be read as a sentence according to their side effects.
149 |
150 | **Preferred:**
151 | ```swift
152 | x.insert(y, at: z) // x, insert y at z
153 | x.subViews(havingColor: y) // x's subviews having color y
154 | x.capitalizingNouns() // x, capitalizing nouns
155 | ```
156 |
157 | **Not Preferred:**
158 | ```swift
159 | x.insert(y, position: z)
160 | x.subViews(color: y)
161 | x.nounCapitalize()
162 | ```
163 |
164 | ### Empty Return Types
165 |
166 | When specifying return type for functions, methods or closures that return no value, favor the type alias `Void` over empty tuple `()`.
167 |
168 | **Preferred:**
169 | ```swift
170 | func performTask(_ completion: @escaping (Bool) -> Void)
171 | ```
172 |
173 | **Not Preferred:**
174 | ```swift
175 | func performTask(_ completion: @escaping (Bool) -> ())
176 | ```
177 |
178 | ## File structure
179 |
180 | You should not define multiple public/internal types (ie class, struct, enum) in the same file; each type should have its own file.
181 |
182 | The following list should be the standard organization of all your Swift files, in this specific order:
183 |
184 | Before the type declaration:
185 |
186 | * Private Class/Struct/Enum
187 |
188 | Inside the type declaration:
189 |
190 | * Override Properties
191 | * Properties
192 | * Static/Class Variables
193 | * Static/Class Functions
194 | * Init/Deinit
195 | * Override Functions
196 | * Instance Functions
197 |
198 | After the type declaration:
199 |
200 | * Extensions
201 |
202 | Each section above should be organized by accessibility:
203 |
204 | * Open
205 | * Public
206 | * Internal
207 | * Fileprivate
208 | * Private
209 |
210 | When implementing a protocol you should create an extension of your class that lives in the same file to separate the core logic of your class and your protocol implementation.
211 |
212 | ### Enum & Protocol
213 |
214 | All enums should live in their own file, except in cases where the enum is declared as private. In cases where the enum is declared private, declare the enum at the top of the file, above the type declaration.
215 |
216 | *Rationale*: With enum and protocol types Swift allows defining functions and extensions. Because of that these types can become complex which is why they should be defined in their own file.
217 |
218 | ### Usage of MARK / TODO / FIXME
219 |
220 | To help organize your files you may want to use pragma marks to clearly separate your functions, properties and extensions. For extensions, use one MARK per extension. For example, `// MARK: UITableViewDelegate Functions` instead of `// MARK: Extensions`.
221 |
222 | Xcode is also able to display `TODO` and `FIXME` tags directly in the source navigator, you should consider using them to find your notes inside your files.
223 |
224 | `// TODO: implement this feature`
225 |
226 | `// FIXME: fix it it's not working`
227 |
228 | Other conventional comment tags, such as `NOTE` are not recognized by Xcode.
229 |
230 | ## Types
231 |
232 | Prefer Swift native types over Objective-C types when possible. Because Swift types bridge to Objective-C, you should avoid types like NSString and NSNumber in favor of Int or String.
233 |
234 | *Rationale*: Avoid subclassing NSObject or using the @objc flag unless it is required to implement an NSObjectProtocol type. Subclassing NSObject or using the @objc flag automatically creates an Objective-C object that uses dynamic dispatch over the preferred static of Swift which can impact the performance of the app.
235 |
236 | **Preferred:**
237 |
238 | ```swift
239 | class MyClass {
240 | ...
241 | }
242 | ```
243 |
244 | **Not preferred:**
245 |
246 | ```swift
247 | @objc class MyClass {
248 | ...
249 | }
250 | ```
251 |
252 | If you need functionality from an Objective-C type that is not available in its corresponding Swift type (for instance, needing an NSString function that is not available on String), cast your Swift raw type to the corresponding Objective-C type instead of declaring the type as the Objective-C type.
253 |
254 | **Preferred:**
255 |
256 | ```swift
257 | let scale = 5.0
258 | let scaleString = (5.0 as NSNumber).stringValue
259 | let scaleInt = Int(scale)
260 | ```
261 |
262 | **Not preferred:**
263 |
264 | ```swift
265 | let scale: NSNumber = 5.0
266 | let scaleString = scale.stringValue
267 | let scaleInt = scale.integerValue
268 | ```
269 |
270 | Always use Swift equivalent of an Objective-C function whenever possible. For example when manipulating a CGRect variable:
271 |
272 | **Preferred:**
273 | ```swift
274 | let rect = CGRect()
275 | let width = rect.width
276 | let height = rect.height
277 | ```
278 |
279 | **Not preferred:**
280 | ```swift
281 | let rect = CGRect()
282 | let width = CGRectGetWidth(rect)
283 | let height = CGRectGetHeight(rect)
284 | ```
285 |
286 | *Rationale*: Objective-C functions are making the code less readable, also using Swift equivalents will always help transitioning from a Swift version to another.
287 |
288 | ### Type Declarations
289 |
290 | When declaring types, the colon should be placed immediately after the identifier followed by one space and the type name.
291 |
292 | ```swift
293 |
294 | var intValue: Int
295 |
296 | // Do NOT do this
297 | var intValue : Int
298 |
299 | ```
300 |
301 | In all use-cases, the colon should be associated with the left-most item with no spaces preceding and one space afterwards:
302 |
303 | ```swift
304 | let myDictionary: [String: AnyObject] = ["String": 0]
305 | ```
306 |
307 | ### typealias
308 |
309 | Typealias declarations should precede any other type declaration.
310 |
311 | ```swift
312 | // typealias ClosureType = (ParameterTypes) -> (ReturnType)
313 | typealias AgeAndNameProcessor = (Int, String) -> Void
314 |
315 | var intValue: Int
316 |
317 | class Object {
318 |
319 | private var someString = ""
320 |
321 | func returnOne() -> Int {
322 | return 1
323 | }
324 |
325 | }
326 | ```
327 |
328 | If declaring a typealias for protocol conformance, it should be declared at the top of the type declaration, before anything else.
329 |
330 |
331 | ```swift
332 | protocol Configurable {
333 |
334 | associatedtype InputData
335 |
336 | func configure(data: InputData) -> Void
337 |
338 | }
339 |
340 | class ExampleWillNeed {
341 |
342 | var x: String = ""
343 | var y: String = ""
344 |
345 | }
346 |
347 | class Example: Configurable {
348 |
349 | typealias InputData = ExampleWillNeed
350 |
351 | var a: String = ""
352 | var b: String = ""
353 |
354 | func configure(data: InputData) {
355 | a = data.x
356 | b = data.y
357 | }
358 |
359 | }
360 | ```
361 |
362 | ### Type Inference
363 |
364 | Prefer letting the compiler infer the type instead of explicitly stating it, wherever possible:
365 |
366 | ```swift
367 | var max = 0 // Int
368 | var name = "John" // String
369 | var rect = CGRect() // CGRect
370 |
371 | // Do not do:
372 |
373 | var max: Int = 0
374 | var name: String = "John"
375 | var rect: CGRect = CGRect()
376 |
377 | // Ok since the inferred type is not what we wanted:
378 |
379 | var max: Hashable = 0 // Compiler would infer Int, but we only want it to be hashable
380 | var name: String? = "John" // Compiler would infer this not to be optional, but we may need to nil it out later.
381 | ```
382 |
383 | *Rationale* The compiler is pretty smart, and we should utilize it where necessary. It is generally obvious what the
384 | type is going to be in the instances above, so unless we need to be more explicit (as in the last examples above), it is better to omit unneeded words.
385 |
386 | ## Statement Termination
387 |
388 | Unlike Objective-C, omit the use of `;` to terminate statements. Instead, simply use new lines to indicate the end of a statement.
389 |
390 | ```swift
391 | let myVar = 0
392 | doSomething(myVar)
393 |
394 | return
395 | ```
396 |
397 | Avoid multiple statements on a single line.
398 |
399 | ```swift
400 | guard let obj = myObj else { print("Something went wrong"); return; } // Wrong! Instead, place each item on its own line.
401 | ```
402 |
403 | ## Variable Declaration
404 |
405 | For declaring variables, favor `let` instead of `var` unless you need a mutable object or container.
406 |
407 | ```swift
408 | func formatDate(date: NSDate) -> String {
409 | let dateFormatter = NSDateFormatter() // In this case, use `let` since the variable `dateFormatter` never changes once set
410 | dateFormatter.dateStyle = .ShortStyle
411 | return dateFormatter.stringFromDate(date)
412 | }
413 |
414 | func arrays() {
415 | let array = ["Hello", "Ciao", "Aloha"] // use let here since this is an immutable container
416 |
417 | var mutableArray = [String]() // Use var here since this container is mutable
418 | mutableArray.append("Farewell")
419 | mutableArray.append("Arrivederci")
420 | }
421 |
422 | ```
423 |
424 | ## Self
425 |
426 | Never use the `self` modifier except in cases where it is necessary for the compiler or to alleviate conflicts
427 | with other variable declarations.
428 |
429 | ```swift
430 |
431 | class Object {
432 | private var name = ""
433 |
434 | func useName() {
435 | // Let self be implied when it can be understood.
436 | otherObject.doSomethingWithName(name)
437 | setName("Will Smith")
438 | }
439 |
440 | func setName(name: String) {
441 | // Use self here to prevent conflicts with the `name` parameter being passed.
442 | self.name = name
443 | }
444 |
445 | func setNameAsync(newName: String) {
446 | // Use implicit self outside closures...
447 | otherObject.doSomethingWithName(name, then: {
448 | // .. but within, you must use self to ease the compiler.
449 | self.setName("Jason")
450 | })
451 | }
452 | }
453 |
454 | ```
455 |
456 | *Rationale*: The idea behind this is that implicit use of self makes the conditions where you _must_ use self
457 | (for instance, within closures) much more apparent and will make you think more on the reasons why you are using it.
458 | In closures, think about: should `self` be `weak` instead of `strong`? Apple has even rejected a request to enforce use of `self` for this reason, [among others](http://ericasadun.com/2016/01/06/the-swift-evolution-proposal-se-0009-rejection/).
459 |
460 |
461 | ## Bracket Syntax
462 |
463 | For brackets, prefer the Xcode-default syntax of having the opening brace be on the same line as the statement opening it:
464 |
465 | ```swift
466 | final class MyObject {
467 | }
468 |
469 | enum MyEnum {
470 | }
471 |
472 | func doSomething() {
473 | }
474 |
475 | if true == false {
476 | }
477 |
478 | let doSomething: () -> Void = {
479 | }
480 |
481 | ```
482 |
483 | For type declarations, include a single space between the type declaration and the first item implemented within
484 | it:
485 |
486 | ```swift
487 | final class MyObject {
488 |
489 | let value = 0
490 | ```
491 |
492 | In addition, include a space before the type declaration's closing bracket:
493 |
494 | ```swift
495 | final class MyObject {
496 |
497 | let value = 0
498 |
499 | func doSomething() {
500 | value += 1
501 | }
502 |
503 | }
504 | ```
505 |
506 | This also applies to extension declarations:
507 |
508 | ```swift
509 | extension MyObject {
510 |
511 | func doAnotherThing() {
512 | ...
513 | }
514 |
515 | }
516 | ```
517 |
518 | Do not include this extra space in function declarations:
519 |
520 | ```swift
521 | func doSomething() {
522 | let value = 0
523 | }
524 | ```
525 |
526 | *Rationale*: Simply put, this is the Xcode default and standard, and it's not worth fighting. This keeps things consistent
527 | across the board and makes our lives as developers considerably easier.
528 |
529 | ## Force Unwrap
530 |
531 | Unless there is a situation that absolutely calls for it, usage of the force-unwrap operator `(!)` should
532 | be minimized, if not eliminated all together. With the many and varied ways of unwrapping optionals, it is
533 | safer and simpler to declare variables as optional and unwrap them when needing their values than it is
534 | to force-unwrap them and potentially introduce runtime errors into the code base.
535 |
536 | ```swift
537 |
538 | if let text = self.textLabel?.text {
539 | doSomethingWithText(text)
540 | }
541 |
542 | ```
543 |
544 | If you are interoping from Objective-C and the declaration automatically translates into force-unwrapped
545 | parameters, replace them with `?` parameters instead.
546 |
547 | The one exception to this rule are IBOutlets. @IBOutlets may be declared using `!` so long as they are expected
548 | to exist for the lifetime of the view controller object:
549 |
550 | ```swift
551 | @IBOutlet private weak var textLabel: UILabel!
552 |
553 | ```
554 |
555 | ## Error Handling
556 |
557 | The emergence of `try / catch` in Swift 2 has added powerful ways to define and return errors when something fails. The emergence of `ErrorType`
558 | as well for defining errors makes error definitions much more convenient over the cumbersome `NSError`. Because of this, for functions that can have multiple
559 | points of failure, you should always define it as `throws` and return a well-defined `ErrorType`.
560 |
561 | Consider the following contrived example:
562 |
563 | ```swift
564 |
565 | func multiplyEvensLessThan10(evenNumber: Int) -> Int? {
566 | guard evenNumber % 2 == 0 && evenNumber < 10 else {
567 | return nil
568 | }
569 |
570 | return evenNumber * 2
571 | }
572 |
573 | ```
574 |
575 | The function above fails because it only expects evens less than 10 and returns an optional if that is violated. While this works and is simple, it
576 | is more Objective-C than Swift in its composition. The caller may not know which parameter they violated. For Swift, instead consider refactoring it as follows:
577 |
578 | ```swift
579 |
580 | enum NumberError: ErrorType {
581 | case notEven
582 | case tooLarge
583 | }
584 |
585 | func multiplyEvens(evenNumber: Int) throws -> Int {
586 | guard evenNumber % 2 == 0 else {
587 | throw NumberError.NotEven
588 | }
589 |
590 | guard evenNumber < 10 else {
591 | throw NumberError.TooLarge
592 | }
593 |
594 | return evenNumber * 2
595 | }
596 |
597 | ```
598 |
599 | The above, while slightly more cumbersome, this has well-defined benefits:
600 |
601 | * The caller is able to explicitly determine why their call to the function failed and thus can take active steps to recover:
602 |
603 | ```swift
604 | let result: Int
605 | do {
606 | result = try multiplyEvens(3)
607 | } catch NumberError.NotEven {
608 | return 0
609 | } catch NumberError.TooLarge {
610 | print("The Number entered was too large! Try again.")
611 | return -1
612 | } catch {
613 | fatalError("Unhandled error occurred.")
614 | }
615 |
616 | return result
617 | ```
618 |
619 | * Try/catch semantics allow the caller to still retain the old optional functionality if the error is not relevant and they only care about the outcome:
620 |
621 | ```swift
622 | let result: Int? = try? multiplyEvens(1)
623 | ```
624 |
625 | * Or, if the caller knows that it will not violate any of the parameters for a valid input:
626 |
627 | ```swift
628 | let result: Int = try! multiplyEvens(2)
629 | ```
630 |
631 | So, even though we've now modified our API to use swift exceptions, we can still retain the old Objective-C functionality giving the caller the choice
632 | of how they wish to handle the result of this failable operation.
633 |
634 | ### NSError
635 |
636 | In general, you should avoid `NSError` in Swift in favor of defining your own `ErrorType`. However, in the event you do need to use `NSError` (for interop with Objective-C, for instance):
637 |
638 | * Define a proper domain for your `NSError`. This should be specific to your module and ideally would be reflective of your bundle identifier (e.g. `com.prolificinteractive.MyApp`).
639 | * Define a list of the various error codes and what they translate to. These should be some sort of easily readable constant or enum value so that way the caller is able to determine what exactly failed.
640 | * In the userInfo, include _at least_ a localized description (`NSLocalizedDescriptionKey`) that accurately and concisely describes the nature of the error.
641 |
642 | ## Access Modifiers
643 |
644 | Specify access modifiers only when they are needed and required by the compiler. For `internal` types and functions, do not explicitly specify the access modifier since all entities in Swift are `internal` by default.
645 |
646 | ```swift
647 | final class Object {
648 |
649 | var myInt: Int
650 |
651 | private func doWork() {
652 | ...
653 | }
654 |
655 | }
656 |
657 | ```
658 |
659 | Further, the access modifier should always be presented first in the list before any other modifiers:
660 |
661 | ```swift
662 | // Good!
663 | private unowned var obj: Object
664 |
665 | func doSomething() {
666 | }
667 |
668 | // Wrong!
669 | weak public var obj: Object?
670 | ```
671 |
672 | ## Imports
673 |
674 | Import statements should be at the very top of the code file, and they should be listed in alphabetical order.
675 |
676 | ```swift
677 | import AFNetworking
678 | import Foundation
679 | import ReactiveCocoa
680 | import RealmSwift
681 | import UIKit
682 | ```
683 |
684 | The exception is for imports that are for testing only; they should be placed at the bottom of the list, in alphabetical order:
685 |
686 | ```swift
687 | import AFNetworking
688 | import UIKit
689 | @testable import MyLibrary
690 | ```
691 |
692 | ## Structs & Classes
693 |
694 | In Swift, structs maintain value semantics which means their values are copied when assigned. Classes, on the other hand, act like pointers from C
695 | and Objective-C; they are called reference types and the internal data is shared amongst instances of assigning.
696 |
697 | When composing your types, consider carefully what they're going to be used for before choosing what they should end up being. In general,
698 | consider structs for types that are:
699 |
700 | * Immutable
701 | * Stateless
702 | * Have a definition for equality
703 |
704 | Swift structs also have other, tangible benefits as well:
705 |
706 | * Faster
707 | * Safer due to copying rather than referencing
708 | * Thread safe -- copies allow mutations to happen independently of other instances.
709 |
710 | In general, you should favor structs and protocols over classes; even in cases where polymorphism would dictate the usage of a class, consider if you can
711 | achieve a similar result via protocols and extensions. This allows you to achieve polymorphism via *composition* rather than *inheritance*.
712 |
713 | ## Nil Checking
714 |
715 | Favor `if-let` checking over direct nil checking in all cases except when the result of this check is required:
716 |
717 | ```swift
718 | guard let item = myItem else {
719 | return
720 | }
721 |
722 | doSomethingWith(item)
723 | ```
724 |
725 | ```swift
726 | if let _ = error { // Prefer this over `if error != nil`
727 | fatalError()
728 | }
729 | ```
730 |
731 | ```swift
732 | func isError(error: Error?) -> Bool {
733 | return (error != nil) // In this case, we need the result of the bool, and this is much cleaner than the other options.
734 | }
735 | ```
736 |
737 | For style suggestions regarding nil checking visit our [best practices](https://github.com/prolificinteractive/swift-style-guide/blob/master/BestPractices.md) section.
738 |
739 | ## Implicit Getters
740 |
741 | When overriding only the getter of a property, omit the use of `get`:
742 |
743 | ```swift
744 | var myInt: Int {
745 | return 0
746 | }
747 |
748 | // Do not do this:
749 | var myInt: Int {
750 | get {
751 | return 0
752 | }
753 | }
754 |
755 | ```
756 |
757 | For all other cases, specify the modifier as needed (`set`, `didSet`, etc.). This is compiler enforced.
758 |
759 | *Rationale* The getter is implied enough to make sense without having to make it explicitly. It also cuts down on
760 | unnecessary verbiage and spacing to make code clearer.
761 |
762 | ## Enums
763 |
764 | For enum declarations, declare each enum case on a new line with its own `case` statement instead of a comma-separated list.
765 |
766 | ```swift
767 | enum State {
768 | case open
769 | case closed
770 | case pending
771 | case faulted
772 | }
773 | ```
774 |
775 | Prefer singular case for enum names instead of plural: `State` vs. `States`:
776 |
777 | ```swift
778 | var currentState = State.open
779 | var previousState = States.closed // Reads less clearly than the previous option.
780 | ```
781 |
782 | For enums with raw values, declare the raw value on the same line as its declaration:
783 |
784 | ```swift
785 | enum HTTPMethod: String {
786 | case get = "GET"
787 | case post = "POST"
788 | }
789 | ```
790 |
791 | For any other functions or properties associated with the enum, place them after the last case item in the enum list:
792 |
793 | ```swift
794 | enum State {
795 | case open
796 | case closed
797 | case pending
798 | case faulted
799 |
800 | func nextState() -> State {
801 | ...
802 | }
803 | }
804 | ```
805 |
806 | In cases where the enum's type name can be omitted, do so:
807 |
808 | ```swift
809 | let state = State.open
810 |
811 | if state == .closed { ... // Prefer .closed instead of State.closed
812 | ```
813 |
814 |
815 | ## Use of `final`
816 |
817 | Classes should always be marked as `final` unless they are being used as a base class for another type. In instances where a class can be subclassed,
818 | any function or variable that should not be overridden by a subclass should be diligently marked as `final`.
819 |
820 | ```swift
821 | // Not built for inheritance.
822 | final class Object {
823 |
824 | }
825 |
826 | // Purposefully utilizable as a base class
827 | class BaseClass {
828 |
829 | func doSomething () {
830 | }
831 |
832 | // Properly marked as final so subclasses cannot override
833 | final func update() {
834 | }
835 |
836 | }
837 |
838 | final class SubClass: BaseClass {
839 |
840 | override func doSomething() {
841 | update()
842 | }
843 |
844 | }
845 |
846 | ```
847 |
848 |
849 | *Rationale* Subclassing in instances where the original class was not built to support subclasses can be a common source of bugs. Marking classes as `final`
850 | indicates that it was developed under the assumption that it would act on its own without regard for subclasses.
851 |
852 | ## Operators
853 |
854 | ### Operator Overloading
855 |
856 | Operator overloading is not recommended. Overloads often lead to ambiguous semantics, unintuitive behaviours and obscurities that are difficult for everyone to understand except the person who wrote them. Instead opt for less succinct, yet more descriptive function definitions throughout your code.
857 |
858 | ### Custom Operators
859 |
860 | Be wary of defining entirely new operators, unless your use case specifically requires it. In some situations borrowing an operator that is defined in the standard library of another language makes sense, such as operators specific to high level scientific or mathematical problem solving. The behaviour of your custom operator should be intuitive and obvious. Its semantics should not conflict with existing Swift operators.
861 |
862 | When defining a custom operator, be clear and use exhaustive documentation. Provide an example use of the operator within your documentation that others will easily understand. Define the new operator in the same file as the type definition that is making use of it.
863 |
864 | ```swift
865 | /// Defines a postfix operator used to
866 | /// add 3 to the value of an integer.
867 | postfix operator +++
868 |
869 | /// Adds a value of 3 to an Integer
870 | /// by appending the postfix operator.
871 | ///
872 | /// Eg. let result = 3+++
873 | /// (result is now 6)
874 | ///
875 | /// - Parameter n: integer to add 3 to
876 | /// - Returns: the value of n plus 3
877 | postfix func +++(n: Int) -> Int {
878 | return n + 3
879 | }
880 | ```
881 |
882 | Ensure there is always an existing function available that can be used as an alternative to the custom operator if required. Consumers of your type interface should be able to choose between using your custom operator as a shortcut, or using the function for further clarity.
883 |
884 | ## Documentation
885 |
886 | Well documented code is critical to help other developers understand what the code is doing. Every **open**, **public** and **internal** types should be documented.
887 | Additionally developers should annotate any private piece of code when its behavior is not trivial using the regular comment syntax `//`.
888 |
889 | See our [best practices](BestPractices.md#documentation) about documenting the code.
890 |
891 | *Rationale* A code without documentation is harder to understand, it is a good practice to document your code to help other developers understand the project, especially when it contains public APIs.
892 |
--------------------------------------------------------------------------------