├── 1.Code_Formatting.md ├── 2.Naming_Conventions.md ├── 3.Coding_Style.md ├── 4.SwiftLint_Rules.md └── README.md /1.Code_Formatting.md: -------------------------------------------------------------------------------- 1 | ### [Index](README.md) 2 | 3 | # Code Formatting 4 | 5 | - 1 - Indentation must be done using tabs, each tab has 4 spaces width (set *Xcode > Preferences > Text Editing > Indentation*) 6 | - 2 - Always avoid long lines; max line length should be 160 characters (set *XCode > Preferences > Text Editing > Page Guide Column*) 7 | - 3 - Enable automatic Trim Trailing Whitespace (set *XCode > Preferences > Text Editing > Automatically trim trailing whitespace & Including whitespace-only lines*) 8 | - 4 - Never place place opening braces on new lines ([1TBS convention](https://en.m.wikipedia.org/wiki/Indentation_style#1TBS)). 9 | 10 | ```swift 11 | class MyClass { 12 | func myMethod() { 13 | if x == y { 14 | /* ... */ 15 | } else if x == z { 16 | /* ... */ 17 | } else { 18 | /* ... */ 19 | } 20 | } 21 | /* ... */ 22 | } 23 | ``` 24 | 25 | - 5 - 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. 26 | 27 | ```swift 28 | // Property Type 29 | let aProperty: MyPropertyClass 30 | 31 | // Dictionary 32 | let aDictionary: [String: Int] = [ 33 | "key1": 2, 34 | "key2": 3 35 | ] 36 | 37 | // Function 38 | func aFunction(argA: U, argB: T) where T.RelatedType == U { 39 | /* ... */ 40 | } 41 | // Calling a Function 42 | myFunction(argument: "MyArgument") 43 | 44 | // Superclasses 45 | class Dog: Wolf { 46 | /* ... */ 47 | } 48 | // protocols 49 | extension PirateViewController: UITableViewDataSource { 50 | /* ... */ 51 | } 52 | ``` 53 | 54 | - 6 - There should be a space following a comma. 55 | 56 | ```swift 57 | let anArray = ["a", "b", "c"] 58 | ``` 59 | 60 | - 7 - There should be a space before and after a binary operation (`+`,`-`,`==`,`>` ...). No space must be apped after `(` and before `)`. 61 | 62 | ```swift 63 | let myValue = 20 + (30 / 2) * 3 64 | if 1 + 1 == 3 { 65 | /* ... */ 66 | } 67 | ``` 68 | 69 | - 8 - Always follow the Xcode's recommended rules about indentation style (basically your code should not change if you force indentation using CTRL-I shortcut). 70 | When declaring a function that span multiple lines prefer the style used by Xcode: 71 | 72 | ```swift 73 | // Xcode indentation for a function declaration that spans multiple lines 74 | func myFunction(parameterOne: String, 75 | parameterTwo: String, 76 | parameterThree: String) { 77 | // Xcode indents to here for this kind of statement 78 | print("\(parameterOne) \(parameterTwo) \(parameterThree)") 79 | } 80 | ``` 81 | 82 | ```swift 83 | // Xcode indentation for a multi-line `if` statement 84 | if myFirstValue > (mySecondValue + myThirdValue) 85 | && myFourthValue == .someEnumValue { 86 | 87 | // Xcode indents to here for this kind of statement 88 | print("Hello, World!") 89 | } 90 | ``` 91 | 92 | - 9 - When calling a function with many parameters (or with a long line), put each argument on a separate line with a single extra indentation. 93 | 94 | ```swift 95 | myAwesomeFunctionWithLotsOfArgs( 96 | firstArgument: "Hello, I am a string", 97 | secondArgument: "Test", 98 | thirdArgument: 2) 99 | ``` 100 | 101 | - 10 - When dealing with `Array` or `Dictionary` with a large amount of elements consider splitting it in multiple lines and treat the `[` and `]` as if they were braces in a method, `if` statement, etc (same for Closures). 102 | 103 | ```swift 104 | someFunctionWithABunchOfArguments( 105 | someStringArgument: "hello I am a string", 106 | someArrayArgument: [ 107 | "dadada daaaa daaaa dadada daaaa daaaa dadada daaaa daaaa", 108 | "string one is crazy - what is it thinking?" 109 | ], 110 | someDictionaryArgument: [ 111 | "dictionary key 1": "some value 1, but also some more text here", 112 | "dictionary key 2": "some value 2" 113 | ], 114 | someClosure: { parameter1 in 115 | print(parameter1) 116 | }) 117 | ``` 118 | 119 | - 11 - For empty arrays and dictionaries, prefer type annotation. (For an array or dictionary assigned to a large, multi-line literal, use type annotation.) 120 | 121 | ```swift 122 | // PREFERRED 123 | var names: [String] = [] 124 | var lookup: [String: Int] = [:] 125 | // NOT PREFERRED 126 | var names = [String]() 127 | var lookup = [String: Int]() 128 | ``` 129 | 130 | - 12 - Prefer using local constants to **avoid multi-line predicates if possible**. 131 | 132 | Use: 133 | 134 | ```swift 135 | let firstCondition = x == firstReallyReallyLongPredicateFunction() 136 | let secondCondition = y == secondReallyReallyLongPredicateFunction() 137 | let thirdCondition = z == thirdReallyReallyLongPredicateFunction() 138 | if firstCondition && secondCondition && thirdCondition { 139 | // do something 140 | } 141 | ``` 142 | 143 | Instead of: 144 | 145 | ```swift 146 | if x == firstReallyReallyLongPredicateFunction() 147 | && y == secondReallyReallyLongPredicateFunction() 148 | && z == thirdReallyReallyLongPredicateFunction() { 149 | // do something 150 | } 151 | ``` 152 | 153 | - 13 - Avoid parenthesis in control flows, in Swift standard they're not necessary: 154 | 155 | ```swift 156 | // PREFERRED 157 | if x == y { 158 | /* ... */ 159 | } 160 | // NOT PREFERRED 161 | if (x == y) { 162 | /* ... */ 163 | } 164 | ``` 165 | 166 | - 14 - There should one blank line between methods. This aid visual clarity and organization of the code. 167 | Inside a method/function whitespace should separate functionality; if you have too much sections separated by space often it means you should refactor into several different methods ([separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns)). 168 | - 15 - Hide non-shared, implementation details inside the extension using `private` access control. 169 | - 16 - Free functions (not attached to a class or type) should be used sparingly. When possible, prefer to use a method instead of a free function. This aids in readability and discoverability. You can also extend primary types if acceptable. 170 | Free functions are most appropriate when they aren't associated with any particular type or instance (generics in Swift). 171 | - 17 - Do not use semicolons; Swift does not require a semicolon after each statement in your code. They are only required if you wish to combine multiple statements on a single line. Never write multiple statements on a single line separated with semicolons. 172 | - 18 - Do not use emoji in your code: it's an unnecessary source of friction and it doesn't add to the learning and it interrupts the coding flow. 173 | - 19 - Consider organizing your code by separating method/property/class using `// MARK:`. 174 | 175 | -------------------------------------------------------------------------------- /2.Naming_Conventions.md: -------------------------------------------------------------------------------- 1 | ### [Index](README.md) 2 | 3 | 4 | 5 | # Naming Conventions for Code 6 | 7 | - 1 - Class names does not need to be prefixed using the classic Obj-C naming convention. Swift types are automatically namespaced by the module that contains them. If two names from different modules collide you can disambiguate by prefixing the type name with the module name. 8 | - 2 - Use [Pascal Naming Convention](https://en.wikipedia.org/wiki/Naming_convention_(programming)#Pascal,_Modula-2_and_Oberon) for `struct`, `enum`, `class`, `typedef`, `associatedtype`, `protocols` etc (camel case plus uppercased first letter. 9 | - 3 - Use [Camel Case Convention](https://en.wikipedia.org/wiki/Camel_case) (with initial lowercase letter) for `function`, `method`, `property`, `constant`, `variable`, `argument names`, `enum` cases, etc. 10 | - 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. 11 | 12 | ```swift 13 | // "HTML" is at the start of a constant name, so we use lowercase "html" 14 | let htmlBodyContent: String = "

Hello, World!

" 15 | // Prefer using ID to Id 16 | let profileID: Int = 1 17 | // Prefer URLFinder to UrlFinder 18 | class URLFinder { ... } 19 | ``` 20 | 21 | - 5 - All constants that are instance-independent should be declared as static in order to avoid declaring one constant per instance. 22 | These constants should be placed in a marked section of their class/struct (after a `// MARK:`), or inside a case-less enum (if they can be grouped for a common context). 23 | The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace. 24 | 25 | Prefer: 26 | 27 | ```swift 28 | class MyClassName { 29 | // MARK: - Constants 30 | static let buttonPadding: CGFloat = 20.0 31 | static let indianaPi = 3 32 | static let shared = MyClassName() 33 | } 34 | ``` 35 | 36 | ```swift 37 | class MyClassName { 38 | enum Constants { 39 | static let buttonPadding: CGFloat = 20.0 40 | static let indianaPi = 3 41 | } 42 | } 43 | ``` 44 | 45 | - 6 - Prefer declaring constants in the scope in which they will be used rather than in a central shared file like *Constants.swift*. 46 | - 7 - Avoid ambiguous names for variables, classes etc (for example `RoundAnimatingButton` is preferred to `CustomButton`) 47 | - 8 - Avoid single name variables or abbreviations (for example use `animationDuration` and not `animDur`). 48 | 49 | ```swift 50 | // We don't want to use abbreviations, so don't use 51 | // `VC` instead of `ViewController` 52 | let popupVC: UIViewController // popUpViewController is preferred 53 | 54 | // for the same reason... 55 | let animDur: TimeInterval // animationDuration is preferred 56 | ``` 57 | 58 | - 9 - Include type information in variable/constant names only when it's not obvious otherwise. 59 | 60 | ```swift 61 | class Person { 62 | // Its okay to omit 'String' in variable name because it's obvious that it's a string from property name itself. 63 | let firstName: String 64 | // When it's not obvious add the name 65 | let personImageView: UIImageView 66 | } 67 | ``` 68 | 69 | - 10 - When working with `IBOutlet` make sure to add the outlet type at the end of the name. 70 | 71 | ```swift 72 | // PREFERRED 73 | @IBOutlet weak var submitButton: UIButton! 74 | @IBOutlet weak var emailTextField: UITextField! 75 | // NOT PREFERRED 76 | @IBOutlet weak var btnSubmit: UIButton! // type is added at the start and it's abbreviated 77 | @IBOutlet weak var buttonSubmit: UIButton! // type must be placed at the end 78 | ``` 79 | 80 | - 11 - When naming function arguments, make sure that the function can be read easily to understand the purpose of each argument. 81 | - 12 - A Protocol should be named as nouns if they describe what something is doing (e.g. `Collection`) and using the suffixes `able`, `ible`, or `ing` if it describes a capability (e.g. `Equatable`, `LogReporting`). 82 | If neither of those options makes sense for your use case, you can add a `Protocol` suffix to the protocol's name as well. 83 | 84 | 85 | 86 | # File Naming Conventions 87 | 88 | - 1 - A file containing a single type `MyType` is named `MyType.swift`. 89 | - 2 - A file containing a type `MyType` and some top-level helper functions is also named `MyType.swift`. (The top-level helpers are not the primary entity.) 90 | - 3 - A file containing a single extension to a type `MyType` that adds conformance to a protocol `MyProtocol` is named `MyType+MyProtocol.swift`. 91 | - 4 - A file containing multiple extensions to a type `MyType` that add conformances, nested types, or other functionality to a type can be named more generally, as long as it is prefixed with `MyType+`; for example, `MyType+Additions.swift`. 92 | - 5 - A file containing related declarations that are not otherwise scoped under a common type or namespace (such as a collection of global mathematical functions) can be named descriptively; for example, `Math.swift`. 93 | 94 | 95 | -------------------------------------------------------------------------------- /3.Coding_Style.md: -------------------------------------------------------------------------------- 1 | ### [Index](README.md) 2 | 3 | # Coding Style 4 | 5 | - [General Guidelines](#general_guidelines) 6 | - [Variables](#variables) 7 | - [Constants](#constants) 8 | - [Tuples](#tuples) 9 | - [Access Modifiers](#access_modifiers) 10 | - [Custom Operators](#custom_operators) 11 | - [Switch & Enums](#switch_enums) 12 | - [Optionals](#optionals) 13 | - [Protocols](#protocols) 14 | - [Properties](#properties) 15 | - [Ternary Operator](#ternary_operator) 16 | - [Closures](#closures) 17 | - [Delegates](#delegates) 18 | - [Array](#array) 19 | - [Using `guard`](#guard) 20 | - [Error Handling](#error_handling) 21 | - [Unused Code](#unused_code) 22 | - [Importing Modules](#importing_modules) 23 | - [Using of `self`](#using_self) 24 | - [Classes or Structs](#classes_structs) 25 | - [Loops](#loops) 26 | - [Documentation & Comments](#doc_comments) 27 | 28 | 29 | ## General Guidelines 30 | 31 | - 1 - Prefer the composition with `map`, `filter`, `reduce` and other similar functional programming operators over iterating when transforming from one collection to another. 32 | Make sure to avoid using closure that have side effects when using these methods. 33 | 34 | ```swift 35 | // PREFERRED 36 | let stringOfInts = [1, 2, 3].flatMap { String($0) } 37 | // DISCOURAGED 38 | var stringOfInts: [String] = [] 39 | for integer in [1, 2, 3] { 40 | stringOfInts.append(String(integer)) 41 | } 42 | ``` 43 | 44 | ```swift 45 | // PREFERRED 46 | let evenNumbers = [4, 8, 15, 16, 23, 42].filter { $0 % 2 == 0 } 47 | // NOT PREFERRED 48 | var evenNumbers: [Int] = [] 49 | for integer in [4, 8, 15, 16, 23, 42] { 50 | if integer % 2 == 0 { 51 | evenNumbers.append(integer) 52 | } 53 | } 54 | ``` 55 | 56 | - 2 - Double check retain cycles when creating delegates/protocols; typically, these properties should be declared `weak`. 57 | - 3 - Double check for `self` to avoid retain cycles (Capture List on [Swift doc](https://docs.swift.org/swift-book/LanguageGuide/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-XID_163)) 58 | 59 | ```swift 60 | myFunction() { [weak self] (error) -> Void in 61 | // you can do this 62 | self?.doSomething() 63 | 64 | // or you can do this 65 | guard let strongSelf = self else { 66 | return 67 | } 68 | 69 | strongSelf.doSomething() 70 | } 71 | ``` 72 | 73 | - 4 - Don’t use shorthand for class methods since it is generally more difficult to infer the context from class methods as opposed to enums. 74 | - 5 - When writing method think if it is intended to be overridden or not (if not and it is does need to be tested you can mark it explicitly with `final` keyword). `final` methods result in improved compilation times so it's good to be used when applicable. 75 | - 6 - Prefer `static` to `class` when declaring a function or a property associated with a class. Only use `class` if you specifically need the functionality of overriding that function or property in a subclass, though consider using a `protocol` to achieve this instead. 76 | - 7 - If you have a function that takes no arguments, has no side effects and return some object or value prefer using a computed property instead of a function: 77 | 78 | ```swift 79 | // NOT PREFERRED 80 | function fullName() -> String { 81 | return "\(self.name) \(self.surname)" 82 | } 83 | // PREFERRED 84 | public var fullName: String { 85 | return "\(self.name) \(self.surname)" 86 | } 87 | ``` 88 | 89 | 90 | ## Variables 91 | 92 | - 1 - Prefer `let` to `var` if possible. A good technique is to assume everything is `let` and only change it to `var` if required to mutate. 93 | - 2 - If the value of the property isn't known until creation, it can still be declared `let`: [assigning constant properties during initialization](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID212). 94 | - 3 - Prefer not declaring types for constants or variables if they can be inferred anyway. 95 | - 4 - When declaring variables you should be verbose, but not too verbose. Make the name descriptive: 96 | 97 | ```swift 98 | // Dictionary is redundant 99 | var someDictionary: Dictionary = [String: String]() 100 | // CGPoint is repeated 101 | var somePoint: CGPoint = CGPoint(x:100, y: 200) 102 | // b is not a descriptive name 103 | var b = Bool(false) 104 | ``` 105 | 106 | - 5 - Avoid repeating type information. Once should be enough. 107 | 108 | 109 | ## Constants 110 | 111 | - 1 - Where possible, keep constants private to the file they are related to. 112 | - 2 - Define constants for unchanging pieces of data in the code. Some examples are CGFloat constants for cell heights, string constants for cell identifiers, key names (for KVC and dictionaries), or segue identifiers. 113 | - 3 - If the constant is declared within a class or struct, it must be declared `static` to avoid declaring one constant per instance. 114 | - 4 - Avoid naming constant with `k` prefixes. 115 | - 5 - File-level constants must be declared with `fileprivate` let (omit it if constant must be used outside) 116 | 117 | 118 | ## Tuples 119 | 120 | - 1 - If a function returns multiple value use a named tuple instead (you can omit naming if return type is obvious). If have 3 or more items in a tuple consider replacing it with a `struct` or `class` instead. 121 | - 2 - If you use a certain tuple more than once, consider using a `typealias` (ie. `public typealias Address = (name: String, number: Int)`. 122 | 123 | 124 | ## Access Modifiers 125 | 126 | - 1 - Access modifier must be placed first declaring a property. 127 | 128 | ```swift 129 | // PREFERRED 130 | private static let myPrivateVar: Int 131 | 132 | // NOT PREFERRED 133 | static private let myPrivateVar: Int 134 | ``` 135 | 136 | - 2 - The access modifier keyword should be placed inline. 137 | 138 | ```swift 139 | // PREFERRED 140 | open class MyClass { 141 | /* ... */ 142 | } 143 | 144 | // NOT PREFERRED 145 | open 146 | class MyClass { 147 | /* ... */ 148 | } 149 | ``` 150 | 151 | - 3 - Don't write `internal` modifier unless needed, it's the default scope for any var. 152 | - 4 - When you need to set a variable open for unit testing mark it as `internal` to use `@testable import Module`. 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. 153 | 154 | ```swift 155 | /** 156 | This property defines the pirate's name. 157 | - warning: Not `private` for `@testable`. 158 | */ 159 | let myVar = "A Value" 160 | ``` 161 | 162 | - 5 - Prefer `private` to `fileprivate` where possible. 163 | - 6 - If you need to set something to be subclassable outside the module prefer using `open` over `public`. 164 | 165 | 166 | ## Custom Operators 167 | 168 | - 1 - The creation of custom operator should be always avoided in order to make the codebase less readable. If you need to create a custom operator you can do it with a named function. 169 | Remember you can always override existing operastors to support new types (especially when comparing using `==`) while preserving the original semantics. 170 | For more guidance on best practices on this matter, view the guidelines at the bottom of this [NSHipster article](http://nshipster.com/swift-operators/#guidelines-for-swift-operators). 171 | 172 | 173 | ## Switch & Enums 174 | 175 | - 1 - `break` keyword in switch statement is not required at the end of the scope unless to avoid execution. You can avoid it. 176 | - 2 - When using a switch statement with a finite set of possibilities do not use `default` case to create a case for unused cases but place them at the bottom followed with a `break` to prevent further execution. 177 | - 3 - `case` must be aligned at the same level of `switch` as for Swift standards. 178 | - 4 - When defining an associated value for an `enum` be sure to describe explicitly it (ie. `case animated(duration: TimeInterval` and not `case animated(TimeInterval)`). 179 | - 5 - Prefer using list cases over `fallthrough` keyword (ie. `case 1, 2, 3:`) 180 | - 6 - If a case of a switch shouldn't be reached for the scope prefer manage it (with asser or throwing an error) over silently fail: 181 | 182 | ```swift 183 | func doSomethingWithNumber(_ digit: Int) throws { 184 | switch digit { 185 | case 0, 1, 2, 3, 4, 5: 186 | /* ... */ 187 | default: 188 | throw Error(message: "Cannot handle this value") 189 | } 190 | } 191 | ``` 192 | 193 | - 7 - Avoid writing out an `enum` type where possible - use shorthand (not `MyEnum.enumValue` but directly `.enumValue`). 194 | 195 | 196 | ## Optionals 197 | 198 | - 1 - **Avoid force unwrapping optionals** by using `!`, `as!` or `try!` as this will cause your app to crash if the value you are trying to use is nil. Always handle the case. 199 | - 2 - Declare variables and function return types as optional with `?` only where a `nil` value is acceptable. 200 | - 3 - If you don't need the value of an optional but you need to determine or what if its value is `nil` **prefer explicit comparison**. 201 | 202 | ```swift 203 | // PREFERERED 204 | if someOptional != nil { 205 | /* ... */ 206 | } 207 | // NOT PREFERRED 208 | if let _ = someOptional { 209 | /* ... */ 210 | } 211 | ``` 212 | 213 | - 4 - **Avoid using `unowned`**. You can think about it as a `weak` property that is implicitly unwrapped; since we don't want to have implicit unwraps we should also avoid `unowned` properties. 214 | 215 | ```swift 216 | // PREFERRED 217 | weak var myViewController: UIViewController? 218 | // NOT PREFERRED 219 | weak var myViewController: UIViewController! 220 | unowned var myViewController: UIViewController 221 | ``` 222 | 223 | - 5 - When **unwrapping a variable use the same name of the unwrapped constant/variable** where appropriate. 224 | 225 | ```swift 226 | guard let aValue = aValue else { 227 | /* ... */ 228 | } 229 | ``` 230 | 231 | - 6 - **Use multiple optional binding in an `if`** let statement where possible to avoid the pyramid of doom: 232 | 233 | ```swift 234 | if let id = json[Constants.id] as? Int { 235 | if let firstName = json[Constants.firstName] as? String { 236 | if let lastName = json[Constants.lastName] as? String { 237 | if let initials = json[Constants.initials] as? String { 238 | /* ... */ 239 | } 240 | } 241 | } 242 | } 243 | ``` 244 | 245 | Correct 246 | 247 | ```swift 248 | if 249 | let id = json[Constants.Id] as? Int, 250 | let firstName = json[Constants.firstName] as? String, 251 | let lastName = json[Constants.lastName] as? String, 252 | let initials = json[Constants.initials] as? String { 253 | /* ... */ 254 | } 255 | ``` 256 | 257 | - 7 - When using `guard`, `if`, or while to unwrap multiple optionals, put each constant and/or variable onto its own line, followed by a `,` except for the last line, which should be followed by `else {` for guard (though this may be on its own line), or `{` for if and while. 258 | 259 | ```swift 260 | if 261 | let constantOne = valueOne, 262 | let constantTwo = valueTwo, 263 | let constantThree = valueThree { 264 | // Code 265 | } 266 | ``` 267 | 268 | 269 | ## Protocols 270 | 271 | - 1 - When implementing protocols you can organize your code: 272 | 273 | - 1 Using `// MARK:` comments to separate protocol implementation from the rest of the code. 274 | - 2 Creating an extension outside your `class`/`struct` implementation but inside the same source file. 275 | 276 | Note: when using #2 methods in extension can't be overridden by an eventual subclass and it makes unit tests difficult to be made. BTW #2 allows a more cleaner separation of concerns. 277 | 278 | - 2 - If your protocol should have [optional methods](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID284), it must be declared with the `@objc` attribute. 279 | - 3 - If more than one class uses the same protocol, declare it in its own file. 280 | - 4 - Limit delegate protocols to classes only by adding `class` to the protocol's inheritance list (as discussed in [Class-Only Protocols](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID281)). 281 | 282 | 283 | ## Properties 284 | 285 | - 1 - If you are making a read-only computed property avoid explicitly declare `get { }` around the block of code. It's not needed. 286 | 287 | ```swift 288 | // PREFERRED 289 | var diameter: Double { 290 | return radius * 2 291 | } 292 | // NOT PREFERRED 293 | var diameter: Double { 294 | get { 295 | return radius * 2 296 | } 297 | } 298 | ``` 299 | 300 | - 2 - Code inside `get {}`, `set {}`, `willSet` and `didSet` must be indent. 301 | - 3 - Use standard `newValue` and `oldValue` for `set/get` blocks. 302 | - 4 - Singleton creation must be done in this way 303 | 304 | ```swift 305 | class NetworkManager { 306 | static let shared = NetworkManager() 307 | /* ... */ 308 | } 309 | ``` 310 | 311 | - 5 - Consider using `lazy` initialization of objects for finer grained control over object lifetime or to reduce allocation if needed in special cases. 312 | 313 | 314 | ## Ternary Operator 315 | 316 | The Ternary operator, `?:` , should only be used when it increases clarity or code neatness. A single condition is usually all that should be evaluated. 317 | 318 | Evaluating multiple conditions is usually more understandable as an if statement or refactored into instance variables. In general, the best use of the ternary operator is during assignment of a variable and deciding which value to use. 319 | 320 | Moreover complex operations with ternary operator are difficult to be evaluated and inferred and should be avoided. 321 | 322 | ```swift 323 | // PREFERRED 324 | let value = 5 325 | result = value != 0 ? x : y 326 | 327 | // NOT PREFERRED 328 | result = a > b ? x = c > d ? c : d : y 329 | ``` 330 | 331 | 332 | ## Closures 333 | 334 | - 1 - When declaring parameters inside a closure you can also omit the type if obvious. 335 | 336 | ```swift 337 | // omitting the type 338 | doSomethingWithClosure() { response in 339 | print(response) 340 | } 341 | 342 | // explicit type 343 | doSomethingWithClosure() { response: NSURLResponse in 344 | print(response) 345 | } 346 | ``` 347 | 348 | - 2 - If does not exceed the limit of line width prefer keeping parameter names on the same line of the opening brace. 349 | - 3 - Only use shorthand argument syntax for simple one-line closure implementations: 350 | 351 | ```swift 352 | let doubled = [2, 3, 4].map { $0 * 2 } // [4, 6, 8] 353 | ``` 354 | 355 | For complex cases explicitly define the argument: 356 | 357 | ```swift 358 | let names = ["George Washington", "Martha Washington", "Abe Lincoln"] 359 | let emails = names.map { fullname in 360 | let dottedName = fullname.replacingOccurrences(of: " ", with: ".") 361 | return dottedName.lowercased() + "@whitehouse.gov" 362 | } 363 | ``` 364 | 365 | - 4 - Use trailing closure syntax only if there is a single closure expression parameter at the end of the argument list. Give the closure parameters descriptive names. 366 | 367 | ```swift 368 | // PREFERRED 369 | UIView.animate(withDuration: 1.0 { 370 | /* ... */ 371 | } 372 | UIView.animate(withDuration: 1.0, animations: { 373 | /* ... */ 374 | }, completion: { finished in 375 | /* ... */ 376 | } 377 | // NOT PREFERRED 378 | UIView.animate(withDuration: 1.0, animations: { 379 | /* ... */ 380 | }, { finished in 381 | /* ... */ 382 | } 383 | ``` 384 | 385 | 386 | ## Delegates 387 | 388 | - 1 - When creating custom delegate methods, an unamed fist parameter should be the delegate source (UIKit contains numerous example of this behaviour) 389 | 390 | ```swift 391 | // PREFERRED 392 | func customPickerView(_ pickerView: CustomPickerView, numberOfRows: Int) 393 | // NOT PREFERRED 394 | func customPickerView(pickerView: CustomPickerView, numberOfRows: Int) 395 | ``` 396 | 397 | 398 | ## Array 399 | 400 | - 1 - Avoid accessing an array directly with subscripts but use accessors such as `.first` or `.last` which guarantee safety when item is not available. 401 | If you can't user accessor make sure to do proper bound checking first. 402 | - 2 - Prefer `for item in items` syntax instead of `for i in 0 ..< items.count` if possible. 403 | - 3 - Prefer `.append()` or `.append(contentsOf:)` method instead of using `+=` operator in order to concatenate array (currently they're more performant, at least with respect to compilation). 404 | 405 | 406 | ## Using `guard` 407 | 408 | - 1 - "Early return" is the preferred way to make sanity checks on a function and it should the preferred way to avoid nested `if` statements. In order to achieve this strategy the use of `guard` is helpful and can improve the readability of the code. 409 | 410 | ```swift 411 | // PREFERRED 412 | func doSomethingWithItem(at index: Int) { 413 | guard index >= 0 && index < item.count else { 414 | // return early because the index is out of bounds 415 | return 416 | } 417 | 418 | let item = item[index] 419 | doSomethingWithObject(item) 420 | } 421 | 422 | // NOT PREFERRED 423 | func doSomethingWithItem(at index: Int) { 424 | if index >= 0 && index < item.count { 425 | let item = item[index] 426 | doSomethingWithObject(item) 427 | } 428 | } 429 | ``` 430 | 431 | This approach is called "Golden Path"; in fact the left-hand margin of the code should be the "golden" or "happy" path. That is, don't nest if statements. Multiple return statements are OK. The guard statement is built for this. 432 | 433 | - 2 - Avoid nested `if` statements and decrease the amount of nested indentation in your code: prefer `guard` statements as opposed to `if` statements to make sanity checks. 434 | 435 | ```swift 436 | // PREFERRED 437 | guard let anObject = anObject else { 438 | return 439 | } 440 | doSomething(with: anObject) 441 | doAnotherStuff(with: anObject) 442 | 443 | // NOT PREFERRED 444 | if let anObject = anObject { 445 | doSomething(with: anObject) 446 | doAnotherStuff(with: anObject) 447 | } 448 | 449 | // NOT PREFERRED 450 | if anObject == nil { 451 | return 452 | } 453 | doSomething(with: anObject!) 454 | doAnotherStuff(with: anObject!) 455 | ``` 456 | 457 | - 3 - Avoid using `guard` statements on a single line. 458 | 459 | ```swift 460 | // PREFERRED 461 | guard let aValue = aValue else { 462 | return 463 | } 464 | 465 | // NOT PREFERRED 466 | guard let aValue = aValue else { return } 467 | ``` 468 | 469 | - 4 - `guard` should be used only if a failure should result in exiting the current context; if the context needs to continue prefer one or more `if` statements instead. The goal of `guard` is to perform early check and returns. 470 | - 5 - If choosing between two different states, it makes more sense to use an if statement as opposed to a guard statement. 471 | 472 | ```swift 473 | // PREFERRED 474 | if aCondition { 475 | /* code A */ 476 | } else { 477 | /* code B */ 478 | } 479 | 480 | // NOT PREFERRED 481 | guard aCondition else { 482 | /* code B */ 483 | return 484 | } 485 | /* code A */ 486 | ``` 487 | 488 | 489 | ## Error Handling 490 | 491 | - 1 - Generally error must be handled in order to provide an action, a recovery options or just a message. Crash on error is never an accepted solution; where possible a recovery must be provided with additional logging. 492 | 493 | Suppose a function `myFunction` which return a `String`, however, at some point it can run into an error. A common approach is to have this function return an optional `String?` where we return `nil` if something went wrong. 494 | 495 | A more viable solution to optional is to use Swift's `try/catch` behaviour especially if it is appropriate to know the reason for the failure. 496 | In general, if a method can "fail", and the reason for the failure is not immediately obvious if using an optional return type, it probably makes sense for the method to throw an error. 497 | 498 | Instead, when the result should semantically potentially be nil as opposed to something going wrong while retrieving the result, it makes sense to return an optional instead of using error handling. 499 | 500 | - 2 - Avoid using the forced-try expression `try!` as a way to ignore errors from throwing methods as this will crash your app if the error actually gets thrown. Safely handle errors using a do statement along with try and catch. A rare reason to use the forced-try expression is similar to force unwrapping optionals; you actually want the app to crash (ideally during debugging before the app ships) to indicate an implementation error. An example of this would be loading a bundle resource that should always be there unless you forgot to include it or rename it. 501 | 502 | 503 | ## Unused Code 504 | 505 | Unused code (including Xcode template code and placeholder comments) should be removed. 506 | 507 | 508 | ## Importing Modules 509 | 510 | Import only the modules a source file requires. 511 | For example, don't import `UIKit` when importing `Foundation` will suffice. 512 | 513 | 514 | ## Using of `self` 515 | 516 | For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods. 517 | 518 | Use self only when required by the compiler (in `@escaping` closures, or in initializers to disambiguate properties from arguments). 519 | In other words, if it compiles without self then omit it. 520 | 521 | 522 | ## Classes or Structs 523 | 524 | **Common Properties** 525 | - They can define properties to store values and they can define functions 526 | - They can define subscripts to provide access to values with subscript syntax (ie. `items["myValue"]` or `items[1]`). 527 | - They can define initializers to setup their initial state 528 | - They can be extended with extensions 529 | - They can conform to protocols 530 | 531 | Out of the box classes are more versatile than structs (at a cost) and support few more capabilities that structs don't have: 532 | 533 | - Classes can inherit from another classes and support type casting 534 | - Classes can be deinitialized (can call `deinit()` before deallocation) 535 | - You can create one or more *references* to a single class 536 | 537 | **Summary*** 538 | 539 | In fact: 540 | - Classes are [reference types](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_145), they increase their reference count when passed to a function or assigned to a variable or constant. 541 | - Structs are so called [value types](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_144). That means that when a struct is assigned to a variable or constant or passed to a function its value is copied instead of increasing its reference count. 542 | 543 | **Structs or Classes** 544 | 545 | Most of your custom data types should be classes. 546 | - Some situations where you may want to use structs: 547 | - When creating simple, lightweight data types. 548 | - When creating types that are composed of other value types (which would also be expected to be copied rather than referenced). 549 | - When you don't need inheritance. 550 | 551 | References 552 | - Extensive Analysis of [Struct vs Classes](https://medium.com/commencis/stop-using-structs-e1be9a86376f) 553 | - Apple Documentation ["Swift Programming Language Guidelines"](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-ID82). 554 | 555 | 556 | ## Loops 557 | - 1 - Use the enumerated() function if you need to loop over a Sequence and use the index: 558 | 559 | ```swift 560 | for (index, element) in someArray.enumerated() { 561 | /* ... */ 562 | } 563 | ``` 564 | 565 | - 2 - If you are not performing a transform, or if there are side effects do not use `map/compactMap`; use a for in loop instead ([tips](http://www.mokacoding.com/blog/when-to-use-map-flatmap-for/)). 566 | 567 | 568 | ## Documentation & Comments 569 | 570 | Documentation is important; Xcode provides an extensive markup syntax to produce a rich and complete documentation ([read it](https://developer.apple.com/library/archive/documentation/Xcode/Reference/xcode_markup_formatting_ref/Attention.html#//apple_ref/doc/uid/TP40016497-CH29-SW1)). 571 | 572 | Generally code should be clear enough which does not need to be documented. Before adding documentation to your code you should ask yourself if why it needs to be documented. 573 | 574 | If a function is more complicated than a simple O(1) operation, you should generally consider adding a doc comment for the function since there could be some information that the method signature does not make immediately obvious. If there are any quirks to the way that something was implemented, whether technically interesting, tricky, not obvious, etc., this should be documented. 575 | 576 | Documentation should be added for complex classes/structs/enums/protocols and properties. All public functions/classes/properties/constants/structs/enums/protocols/etc. should be documented as well (provided, again, that their signature/name does not make their meaning/functionality immediately obvious). 577 | 578 | After writing a doc comment, you should option click the function/property/class/etc. to make sure that everything is formatted correctly. 579 | 580 | - 1 - Comments should be 160 characters long, as like the rest of the code. 581 | - 2 - Documentation must be inside `/** */` block, even if the doc comment takes up just one line. 582 | - 3 - Avoid prefixing comments line with `*`, its not recessary. 583 | - 4 - Use the built-in 'Add Documentation' shortcut once you made the signature and to use the new syntax of XCode. 584 | - 5 - Complex classes must include a description of the usage with some potential examples as seems appropriate. Remember that markdown syntax is valid in Swift's comment docs. Newlines, lists, etc. are therefore appropriate. 585 | - 6 - When mentioning variables or other portion of code in documentation insert it between ` characters. 586 | - 7 - Documentation should be coincise and complete. 587 | - 8 - Leave comments on their own line. 588 | - 9 - When using `// MARK: -` whatever, leave a newline after the comment. 589 | - 10 - Always leave a space after `//` 590 | 591 | -------------------------------------------------------------------------------- /4.SwiftLint_Rules.md: -------------------------------------------------------------------------------- 1 | ### [Index](README.md) 2 | 3 | # SwiftLint Rules 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift Coding Guidelines 2 | 3 | The following section describe a list of rules, code conducts and best practices used while working on iOS projects using Swift language. 4 | With the help of a set of shared guidelines and automated tools we aim to maintain a higher level of code discipline and increase the reliability of the code during the entire lifecycle of a project. 5 | 6 | The following section describe tools and rules used into the project. 7 | In order to automate the check of the source code by identifying some common and uncommon mistakes [SwiftLint](https://github.com/realm/SwiftLint) tool is used and executed at each build of the project. 8 | 9 | ## Index 10 | - [Code Formatting](1.Code_Formatting.md) 11 | - [Naming Conventions](2.Naming_Conventions.md) 12 | - [Naming Conventions for Code](2.Naming_Conventions.md#code) 13 | - [File Naming Conventions](2.Naming_Conventions.md#files) 14 | - [Coding Style](3.Coding_Style.md) 15 | - [General Guidelines](3.Coding_Style.md#general_guidelines) 16 | - [Variables](3.Coding_Style.md#variables) 17 | - [Constants](3.Coding_Style.md#constants) 18 | - [Tuples](3.Coding_Style.md#tuples) 19 | - [Access Modifiers](3.Coding_Style.md#access_modifiers) 20 | - [Custom Operators](3.Coding_Style.md#custom_operators) 21 | - [Switch & Enums](3.Coding_Style.md#switch_enums) 22 | - [Optionals](3.Coding_Style.md#optionals) 23 | - [Protocols](3.Coding_Style.md#protocols) 24 | - [Properties](3.Coding_Style.md#properties) 25 | - [Ternary Operator](3.Coding_Style.md#ternary_operator) 26 | - [Closures](3.Coding_Style.md#closures) 27 | - [Delegates](3.Coding_Style.md#delegates) 28 | - [Array](3.Coding_Style.md#array) 29 | - [Using `guard`](3.Coding_Style.md#guard) 30 | - [Error Handling](3.Coding_Style.md#error_handling) 31 | - [Unused Code](3.Coding_Style.md#unused_code) 32 | - [Importing Modules](3.Coding_Style.md#importing_modules) 33 | - [Using of `self`](3.Coding_Style.md#using_self) 34 | - [Classes or Structs](3.Coding_Style.md#classes_structs) 35 | - [Loops](3.Coding_Style.md#loops) 36 | - [Documentation & Comments](3.Coding_Style.md#doc_comments) 37 | - [Linter Rules](4.SwiftLint_Rules.md) 38 | 39 | ### References 40 | 41 | The following documents are used as base for this set of rules. 42 | - [Raywenderlich Swift Guidelines](https://github.com/raywenderlich/swift-style-guide) 43 | - [LinkedIn Swift Style Guide](https://github.com/linkedin/swift-style-guide) 44 | - [Github Swift Style Guide](https://google.github.io/swift/) 45 | - [Apple Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/) 46 | --------------------------------------------------------------------------------