├── .swiftlint.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SwiftStyleSettings.plist ├── intrepid-logo.png ├── mark-with-dash.png └── mark.png /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | # Compiled with 0.30.1 rules 2 | 3 | # Don't add any files/directories to the 'include:' section. Everything not 4 | # listed under 'excluded:' should be linted. 5 | # included: 6 | # - Nothing 7 | 8 | excluded: # paths to ignore during linting. Takes precedence over `included`. 9 | - Pods 10 | - Carthage 11 | 12 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit) 13 | 14 | ## Rules 15 | 16 | # enabled_rules_for_documentation: 17 | # - attributes 18 | # - block_based_kvo 19 | # - class_delegate_protocol 20 | # - closing_brace 21 | # - closure_end_indentation 22 | # - closure_parameter_position 23 | # - closure_spacing 24 | # - colon 25 | # - comma 26 | # - compiler_protocol_init 27 | # - contains_over_first_not_nil 28 | # - control_statement 29 | # - custom_rules 30 | # - discarded_notification_center_observer 31 | # - discouraged_direct_init 32 | # - duplicate_imports 33 | # - dynamic_inline 34 | # - empty_parameters 35 | # - empty_parentheses_with_trailing_closure 36 | # - fallthrough 37 | # - file_length 38 | # - first_where 39 | # - force_cast 40 | # - force_try 41 | # - force_unwrapping 42 | # - generic_type_name 43 | # - is_disjoint 44 | # - identifier_name 45 | # - inert_defer 46 | # - implicit_getter 47 | # - implicitly_unwrapped_optional 48 | # - leading_whitespace 49 | # - legacy_cggeometry_functions 50 | # - legacy_constant 51 | # - legacy_constructor 52 | # - legacy_hashing 53 | # - legacy_nsgeometry_functions 54 | # - mark 55 | # - nesting 56 | # - notification_center_detachment 57 | # - no_fallthrough_only 58 | # - object_literal 59 | # - opening_brace 60 | # - operator_usage_whitespace 61 | # - operator_whitespace 62 | # - private_outlet 63 | # - private_unit_test 64 | # - protocol_property_accessors_order 65 | # - redundant_discardable_let 66 | # - redundant_nil_coalescing 67 | # - redundant_objc_attribute 68 | # - redundant_optional_initialization 69 | # - redundant_set_access_control 70 | # - redundant_string_enum_value 71 | # - return_arrow_whitespace 72 | # - statement_position 73 | # - superfluous_disable_command 74 | # - switch_case_alignment 75 | # - syntactic_sugar 76 | # - trailing_comma 77 | # - trailing_newline 78 | # - trailing_semicolon 79 | # - trailing_whitespace 80 | # - type_body_length 81 | # - type_name 82 | # - unneeded_break_in_switch 83 | # - unused_closure_parameter 84 | # - unused_control_flow_label 85 | # - unused_enumerated 86 | # - unused_optional_binding 87 | # - unused_setter_value 88 | # - valid_ibinspectable 89 | # - vertical_parameter_alignment 90 | # - vertical_whitespace 91 | # - weak_delegate 92 | # - xctfail_message 93 | 94 | opt_in_rules: 95 | - anyobject_protocol 96 | - closure_body_length 97 | - collection_alignment 98 | - convenience_type 99 | - empty_xctest_method 100 | - explicit_init 101 | - fatal_error_message 102 | - function_default_parameter_at_end 103 | - identical_operands 104 | - joined_default_parameter 105 | - legacy_random 106 | - lower_acl_than_parent 107 | - multiline_arguments 108 | - multiline_function_chains 109 | - multiline_parameters 110 | - nslocalizedstring_key 111 | - overridden_super_call 112 | - prohibited_super_call 113 | - redundant_void_return 114 | - sorted_first_last 115 | - static_operator 116 | - strong_iboutlet 117 | - unavailable_function 118 | - unused_import 119 | - unused_private_declaration 120 | - vertical_parameter_alignment_on_call 121 | - xct_specific_matcher 122 | 123 | disabled_rules: 124 | - array_init 125 | - conditional_returns_on_newline 126 | - cyclomatic_complexity 127 | - discouraged_object_literal 128 | - discouraged_optional_boolean 129 | - discouraged_optional_collection 130 | - empty_count 131 | - empty_enum_arguments 132 | - empty_string 133 | - explicit_acl 134 | - explicit_enum_raw_value 135 | - explicit_self 136 | - explicit_top_level_acl 137 | - explicit_type_interface 138 | - extension_access_modifier 139 | - file_header 140 | - file_name 141 | - for_where 142 | - implicit_return 143 | - let_var_whitespace 144 | - missing_docs 145 | - multiline_arguments_brackets 146 | - multiline_literal_brackets 147 | - multiline_parameters_brackets 148 | - nimble_operator 149 | - no_extension_access_modifier 150 | - no_grouping_extension 151 | - number_separator 152 | - override_in_extension 153 | - pattern_matching_keywords 154 | - prefixed_toplevel_constant 155 | - private_action 156 | - private_over_fileprivate 157 | - prohibited_interface_builder 158 | - quick_discouraged_call 159 | - quick_discouraged_focused_test 160 | - quick_discouraged_pending_test 161 | - redundant_type_annotation 162 | - required_enum_case 163 | - single_test_class 164 | - sorted_imports 165 | - shorthand_operator 166 | - strict_fileprivate 167 | - switch_case_on_newline 168 | - todo 169 | - toggle_bool 170 | - trailing_closure 171 | - unneeded_parentheses_in_closure_argument 172 | - untyped_error_in_catch 173 | - vertical_whitespace_between_cases 174 | - void_return 175 | - yoda_condition 176 | 177 | # These next rules are recommended to be enabled on a project-by-project 178 | # basis with specific configurations that fit the project style. 179 | - function_body_length 180 | - function_parameter_count 181 | - large_tuple 182 | - last_where 183 | - line_length 184 | - literal_expression_end_indentation 185 | - modifier_order 186 | - multiple_closures_with_trailing_closure 187 | - vertical_whitespace_closing_braces 188 | - vertical_whitespace_opening_braces 189 | 190 | ## Rule Configuration 191 | 192 | colon: 193 | apply_to_dictionaries: false 194 | 195 | file_length: 196 | warning: 750 197 | error: 1500 198 | 199 | identifier_name: 200 | excluded: 201 | - id 202 | 203 | lower_acl_than_parent: 204 | severity: error 205 | 206 | nesting: 207 | type_level: 3 208 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | If you want to suggest a change or addition that will help accomplish 2 | [the goals](README.md) of this style guide, please open a pull request that: 3 | 4 | 1. Explains the guideline 5 | 1. Demonstrates the guideline with more-or-less valid example code 6 | 1. Justifies the guideline by explaining the rationale behind it 7 | 8 | Just note that all suggestions are open to discussion and debate! :smile: 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Intrepid Pursuits](intrepid-logo.png) 2 | # Swift Style Guide 3 | 4 | This is the documentation of Intrepid's best practices and style regarding the Swift language. 5 | 6 | ## Making / Requesting Changes 7 | 8 | Feedback and change requests are encouraged! The current maintainers of this style guide are the developers of [Intrepid](http://www.intrepid.io). If you have an issue with any of the existing rules and would like to see something changed, please see the [contribution guidelines](CONTRIBUTING.md), 9 | then open a pull request. :zap: 10 | 11 | ## Goals 12 | 13 | Attempt to encourage patterns that accomplish the following goals: 14 | 15 | 1. Increased rigor, and decreased likelihood of programmer error 16 | 2. Increased clarity of intent 17 | 3. Aesthetic consistency 18 | 19 | ## Table Of Contents 20 | 21 | * [General](#general) 22 | * [SwiftLint](#swiftlint) 23 | * [Whitespace](#whitespace) 24 | * [Code Grouping](#code-grouping) 25 | * [Guard Statements](#guard-statements) 26 | * [Classes, Structs, and Protocols](#classes-structs-and-protocols) 27 | * [Structs vs Classes](#structs-vs-classes) 28 | * [Protocol Naming](#protocol-naming) 29 | * [Types](#types) 30 | * [Type Specifications](#type-specifications) 31 | * [Let vs Var](#let-vs-var) 32 | * [Parameterized Types](#parameterized-types) 33 | * [Operator Definitions](#operator-definitions) 34 | * [Dictionaries](#dictionaries) 35 | * [Type Inference](#type-inference) 36 | * [Enums](#enums) 37 | * [Optionals](#optionals) 38 | * [Force-Unwrapping of Optionals](#force-unwrapping-of-optionals) 39 | * [Optional Chaining](#optional-chaining) 40 | * [Implicitly Unwrapped Optionals](#implicitly-unwrapped-optionals) 41 | * [Access Control](#access-control) 42 | * [Getters](#getters) 43 | * [Referring to self](#referring-to-self) 44 | * [Classes final by default](#make-classes-final-by-default) 45 | * [Functions](#functions) 46 | * [Declarations](#declarations) 47 | * [Naming](#naming) 48 | * [Calling](#calling) 49 | * [Closures](#closures) 50 | * [Closure Specifications](#closure-specifications) 51 | * [Shorthand](#shorthand) 52 | * [Trailing closures](#trailing-closures) 53 | * [Multiple closures](#multiple-closures) 54 | * [Referring to `self`](#referring-to-self) 55 | * [Should I use `unowned` or `weak`](#should-i-use-unowned-or-weak) 56 | 57 | ## General 58 | 59 | ### SwiftLint 60 | 61 | We use the [SwiftLint](https://github.com/realm/SwiftLint) library from Realm to enforce code style practices across our projects. This will be enabled by default for projects using Jenkins Pipelines. There is a `.swiftlint.yml` file [available here](.swiftlint.yml) which is the current general standard for Intrepid projects (used by default for Jenkins). The rules can be changed on a project-by-project basis, but this should be avoided if possible. To use your own SwiftLint file on a project be sure to include the it within the project's directory. 62 | 63 | ### Whitespace 64 | 65 | * Indent using 4 spaces. Never indent with tabs. Be sure to set this preference in Xcode. 66 | * End files with a newline. 67 | * Make liberal use of vertical whitespace to divide code into logical chunks. 68 | * Don’t leave trailing whitespace. 69 | * Not even leading indentation on blank lines. 70 | 71 | ### Code Grouping 72 | 73 | Code should strive to be separated into meaningful chunks of functionality. These larger chunks should be indicated by using the `// MARK: - ` keyword. 74 | 75 | Using just `// MARK: section title` inserts the `section title` into the function menu, bolding it, and giving it a unique section icon (see `View Lifecycle`). 76 | 77 | ![marked section](mark.png) 78 | 79 | Adding the dash, `// MARK: - section title`, not only inserts the `section title` into the function menu, bolding it, and giving it a unique section icon but also adds a separator into the function menu (see light gray line above `View Lifecycle`). This makes it easier to identify grouped code. 80 | 81 | ![marked with dash section](mark-with-dash.png) 82 | 83 | When grouping protocol conformance, always use the name of the protocol and only the name of the protocol 84 | 85 | ##### Like this: 86 | ```Swift 87 | // MARK: - UITableViewDelegate 88 | ``` 89 | 90 | ###### Not this: 91 | ```Swift 92 | // MARK: - UITableViewDelegate Methods 93 | ``` 94 | 95 | ###### -- or -- 96 | 97 | ```Swift 98 | // MARK: - Table View Delegate 99 | ``` 100 | 101 | ### Guard Statements 102 | 103 | Guard statements are meant to be used as early return logic only. They should not be used for regular control flow in place of a traditional control flow statement. 104 | 105 | ##### Single assignment `guard` 106 | ```Swift 107 | guard let value = someMethodThatReturnsOptional() else { return nil } 108 | ``` 109 | 110 | ##### Multi assignment `guard` 111 | ```Swift 112 | guard 113 | let strongSelf = self, 114 | let foo = strongSelf.editing 115 | else { return } 116 | ``` 117 | 118 | ##### Complex Returns `guard` 119 | This is any situation where you'd want to do more work in the guard than just return or throw. 120 | ```Swift 121 | guard let value = someMethodThatReturnsOptional() else { 122 | doSomeNecessaryThing() 123 | return nil 124 | } 125 | ``` 126 | 127 | ##### Complex Returns (Multi-assignment) `guard` 128 | ```Swift 129 | guard 130 | let strongSelf = self, 131 | let foo = strongSelf.editing 132 | else { 133 | doSomeNecessaryThing() 134 | throw Error.FooUnknown 135 | } 136 | ``` 137 | 138 | ## Classes, Structs, and Protocols 139 | 140 | ### Structs vs Classes 141 | 142 | Unless you require functionality that can only be provided by a class (like identity or deinitializers), implement a struct instead. 143 | 144 | Note that inheritance is (by itself) usually _not_ a good reason to use classes, because polymorphism can be provided by protocols, and implementation reuse can be provided through composition. 145 | 146 | For example, this class hierarchy: 147 | 148 | ```swift 149 | class Vehicle { 150 | let numberOfWheels: Int 151 | 152 | init(numberOfWheels: Int) { 153 | self.numberOfWheels = numberOfWheels 154 | } 155 | 156 | func maximumTotalTirePressure(pressurePerWheel: Float) -> Float { 157 | return pressurePerWheel * Float(numberOfWheels) 158 | } 159 | } 160 | 161 | class Bicycle: Vehicle { 162 | init() { 163 | super.init(numberOfWheels: 2) 164 | } 165 | } 166 | 167 | class Car: Vehicle { 168 | init() { 169 | super.init(numberOfWheels: 4) 170 | } 171 | } 172 | ``` 173 | 174 | could be refactored into these definitions: 175 | 176 | ```swift 177 | protocol Vehicle { 178 | var numberOfWheels: Int { get } 179 | } 180 | 181 | extension Vehicle { 182 | func maximumTotalTirePressure(pressurePerWheel: Float) -> Float { 183 | return pressurePerWheel * Float(numberOfWheels) 184 | } 185 | } 186 | 187 | struct Bicycle: Vehicle { 188 | let numberOfWheels = 2 189 | } 190 | 191 | struct Car: Vehicle { 192 | let numberOfWheels = 4 193 | } 194 | ``` 195 | 196 | **_Rationale:_** Value types are simpler, easier to reason about, and behave as expected with the `let` keyword. 197 | 198 | #### Protocol Naming 199 | 200 | Protocols that describe _what something is_ should be named as nouns. 201 | ```Swift 202 | Collection, ViewDelegate, etc. 203 | ``` 204 | Protocols that describe the _capability_ of something should be named using the suffixes `able`, `ible`, or `ing`. 205 | ```Swift 206 | Equatable, Reporting, Sustainable, etc. 207 | ``` 208 | 209 | ## Types 210 | 211 | ### Type Specifications 212 | 213 | When specifying the type of an identifier, always put the colon immediately 214 | after the identifier, followed by a space and then the type name. 215 | 216 | ```swift 217 | class SmallBatchSustainableFairtrade: Coffee { ... } 218 | 219 | let timeToCoffee: NSTimeInterval = 2 220 | 221 | func makeCoffee(type: CoffeeType) -> Coffee { ... } 222 | 223 | func swap(inout a: T, inout b: T) { ... } 224 | ``` 225 | 226 | ### Let vs Var 227 | 228 | Prefer `let`-bindings over `var`-bindings wherever possible 229 | 230 | Use `let foo = …` over `var foo = …` wherever possible (and when in doubt). Only use `var` if you absolutely have to (i.e. you *know* that the value might change, e.g. when using the `weak` storage modifier). 231 | 232 | **_Rationale:_** The intent and meaning of both keywords is clear, but *let-by-default* results in safer and clearer code. 233 | 234 | A `let`-binding guarantees and *clearly signals to the programmer* that its value is supposed to and will never change. Subsequent code can thus make stronger assumptions about its usage. 235 | 236 | It becomes easier to reason about code. Had you used `var` while still making the assumption that the value never changed, you would have to manually check that. 237 | 238 | Accordingly, whenever you see a `var` identifier being used, assume that it will change and ask yourself why. 239 | 240 | ### Parameterized Types 241 | 242 | Methods of parameterized types can omit type parameters on the receiving type when they’re identical to the receiver’s. 243 | 244 | ##### Like this: 245 | ```swift 246 | struct Composite { 247 | … 248 | func compose(other: Composite) -> Composite { 249 | return Composite(self, other) 250 | } 251 | } 252 | ``` 253 | 254 | ###### Not this: 255 | ```swift 256 | struct Composite { 257 | … 258 | func compose(other: Composite) -> Composite { 259 | return Composite(self, other) 260 | } 261 | } 262 | ``` 263 | 264 | **_Rationale:_** Omitting redundant type parameters clarifies the intent, and makes it obvious by contrast when the returned type takes different type parameters. 265 | 266 | ### Operator Definitions 267 | 268 | Use whitespace around operators when defining them. 269 | 270 | ##### Like this: 271 | ```swift 272 | func <| (lhs: Int, rhs: Int) -> Int 273 | func <|< (lhs: A, rhs: A) -> A 274 | ``` 275 | 276 | ###### Not this: 277 | ```swift 278 | func <|(lhs: Int, rhs: Int) -> Int 279 | func <|<(lhs: A, rhs: A) -> A 280 | ``` 281 | 282 | **_Rationale:_** Operators consist of punctuation characters, which can make them difficult to read when immediately followed by the punctuation for a type or value parameter list. Adding whitespace separates the two more clearly. 283 | 284 | #### As Part Of Protocol Conformance 285 | 286 | When defining an operator to conform to a protocol such as `Equatable`, define it within the scope of the extension or type definition that declared the protocol conformance. 287 | 288 | ##### Like this: 289 | ```swift 290 | extension Person: Equatable { 291 | static func == (lhs: Person, rhs: Person) -> Bool { 292 | return lhs.id == rhs.id 293 | } 294 | } 295 | ``` 296 | 297 | ###### Not this: 298 | 299 | ```swift 300 | extension Person: Equatable { } 301 | 302 | func == (lhs: Person, rhs: Person) -> Bool { 303 | return lhs.id == rhs.id 304 | } 305 | ``` 306 | 307 | **_Rationale:_** Better code organization, easier to tell at a glance which operator belongs to which type. 308 | 309 | ### Dictionaries 310 | 311 | When specifying the type of a dictionary, always leave one space after the colon, and no extra spaces around the brackets. 312 | 313 | ##### Like this: 314 | ```swift 315 | let capitals: [Country: City] = [Sweden: Stockholm] 316 | ``` 317 | 318 | ###### Not this: 319 | ```swift 320 | let capitals: [Country: City] = [ Sweden: Stockholm ] 321 | ``` 322 | 323 | For literal dictionaries that exceed a single line, newline syntax is preferable: 324 | 325 | ##### Like this: 326 | ```swift 327 | let capitals: [Country: City] = [ 328 | Sweden: Stockholm, 329 | USA: WashingtonDC 330 | ] 331 | ``` 332 | 333 | ###### Not this: 334 | ```swift 335 | let capitals: [Country: City] = [Sweden: Stockholm, USA: WashingtonDC] 336 | ``` 337 | 338 | ### Type Inference 339 | 340 | Unless it impairs readability or understanding, it preferable to rely on Swift's type inference where appropriate. 341 | 342 | ##### Like this: 343 | ```Swift 344 | let hello = "Hello" 345 | ``` 346 | 347 | ###### Not this: 348 | ```Swift 349 | let hello: String = "Hello" 350 | ``` 351 | 352 | This does not mean one should avoid those situations where an explicit type is required. 353 | 354 | ##### Like this: 355 | ```Swift 356 | let padding: CGFloat = 20 357 | var hello: String? = "Hello" 358 | ``` 359 | 360 | **_Rationale:_** The type specifier is saying something about the _identifier_ so 361 | it should be positioned with it. 362 | 363 | ### Enums 364 | 365 | Enum cases should be defined in `camelCase` with leading lowercase letters. This is counter to Swift 2.x where uppercase was preferred. 366 | 367 | ##### Like This 368 | 369 | ```Swift 370 | enum Directions { 371 | case north 372 | case south 373 | case east 374 | case west 375 | } 376 | ``` 377 | 378 | ###### Not This 379 | 380 | ```Swift 381 | enum Directions { 382 | case North 383 | case South 384 | case East 385 | case West 386 | } 387 | ``` 388 | 389 | **_Rationale:_** Uppercase syntax should be reserved for typed declarations only. 390 | 391 | ## Optionals 392 | 393 | ### Force-Unwrapping of Optionals 394 | 395 | If you have an identifier `foo` of type `FooType?` or `FooType!`, don't force-unwrap it to get to the underlying value (`foo!`) if possible. 396 | 397 | Instead, prefer this: 398 | 399 | ```swift 400 | if let foo = foo { 401 | // Use unwrapped `foo` value in here 402 | } else { 403 | // If appropriate, handle the case where the optional is nil 404 | } 405 | ``` 406 | 407 | Or when unwrapping multiple optionals, prefer this: 408 | 409 | ```swift 410 | if let foo = foo.optionalProperty as? SomeType, 411 | let bar = bars.filter({ $0.isMyBar }).first, 412 | foo.hasBizz, 413 | bar.hasBazz { // Notice the new line between conditionals and execution code 414 | 415 | foo.bizz() 416 | bar.bazz() 417 | } else { 418 | // If appropriate, handle the case where the optionals are nil 419 | } 420 | ``` 421 | 422 | **_Rationale:_** Explicit `if let`-binding of optionals results in safer code. Force unwrapping is more prone to lead to runtime crashes. 423 | 424 | ### Optional Chaining 425 | 426 | Optional chaining in Swift is similar to messaging `nil` in Objective-C, but in a way that works for any type, and that can be checked for success or failure. 427 | 428 | Use optional chaining if you don’t plan on taking any alternative action if the optional is `nil`. 429 | 430 | ```Swift 431 | let cell: YourCell = tableView.ip_dequeueCell(indexPath) 432 | cell.label?.text = “Hello World” 433 | return cell 434 | ``` 435 | 436 | **_Rationale:_** The use of optional binding here is overkill. 437 | 438 | ### Implicitly Unwrapped Optionals 439 | 440 | Implicitly unwrapped optionals have the potential to cause runtime crashes and should be used carefully. If a variable has the possibility of being `nil`, you should always declare it as an optional `?`. 441 | 442 | Implicitly unwrapped optionals may be used in situations where limitations prevent the use of a non-optional type, but will never be accessed without a value. 443 | 444 | If a variable is dependent on `self` and thus not settable during initialization, consider using a `lazy` variable. 445 | 446 | ```Swift 447 | lazy var customObject: CustomObject = CustomObject(dataSource: self) 448 | ``` 449 | 450 | **_Rationale:_** Explicit optionals result in safer code. Implicitly unwrapped optionals have the potential of crashing at runtime. 451 | 452 | ## Access Control 453 | 454 | Top-level functions, types, and variables should always have explicit access control specifiers: 455 | 456 | ```swift 457 | public var whoopsGlobalState: Int 458 | internal struct TheFez {} 459 | private func doTheThings(things: [Thing]) {} 460 | ``` 461 | 462 | However, definitions within those can leave access control implicit, where appropriate: 463 | 464 | ```swift 465 | internal struct TheFez { 466 | var owner: Person = Joshaber() 467 | } 468 | ``` 469 | 470 | When dealing with functionality that relies on ObjC systems such as the target-selector pattern, one should still strive for appropriate access control. This can be achieved through the `@objC` attribute. 471 | 472 | ##### Like this: 473 | ```Swift 474 | @objc private func handleTap(tap: UITapGestureRecognizer) 475 | ``` 476 | 477 | ###### Not this: 478 | ```Swift 479 | public func handleTap(tap: UITapGestureRecognizer) 480 | ``` 481 | 482 | **_Rationale:_** It's rarely appropriate for top-level definitions to be specifically `internal`, and being explicit ensures that careful thought goes into that decision. Within a definition, reusing the same access control specifier is just duplicative, and the default is usually reasonable. 483 | 484 | ### Getters 485 | 486 | When possible, omit the `get` keyword on read-only computed properties and 487 | read-only subscripts. 488 | 489 | ##### Like this: 490 | ```swift 491 | var myGreatProperty: Int { 492 | return 4 493 | } 494 | 495 | subscript(index: Int) -> T { 496 | return objects[index] 497 | } 498 | ``` 499 | 500 | ###### Not this: 501 | ```swift 502 | var myGreatProperty: Int { 503 | get { 504 | return 4 505 | } 506 | } 507 | 508 | subscript(index: Int) -> T { 509 | get { 510 | return objects[index] 511 | } 512 | } 513 | ``` 514 | 515 | **_Rationale:_** The intent and meaning of the first version is clear, and results in less code. 516 | 517 | ### Referring to `self` 518 | 519 | When accessing properties or methods on `self`, leave the reference to `self` implicit by default: 520 | 521 | ```swift 522 | private class History { 523 | var events: [Event] 524 | 525 | func rewrite() { 526 | events = [] 527 | } 528 | } 529 | ``` 530 | 531 | Only include the explicit keyword when required by the language—for example, in a closure, or when parameter names conflict: 532 | 533 | ```swift 534 | extension History { 535 | init(events: [Event]) { 536 | self.events = events 537 | } 538 | 539 | var whenVictorious: () -> Void { 540 | return { 541 | self.rewrite() 542 | } 543 | } 544 | } 545 | ``` 546 | 547 | **_Rationale:_** This makes the capturing semantics of `self` stand out more in closures, and avoids verbosity elsewhere. 548 | 549 | ### Make classes `final` by default 550 | 551 | Classes should start as `final`, and only be changed to allow subclassing if a valid need for inheritance has been identified. Even in that case, as many definitions as possible _within_ the class should be `final` as well, following the same rules. 552 | 553 | **_Rationale:_** Composition is usually preferable to inheritance, and opting _in_ to inheritance hopefully means that more thought will be put into the decision. 554 | 555 | ## Functions 556 | 557 | Specifications around the preferable syntax to use when declaring, and using functions. 558 | 559 | ### Declarations 560 | 561 | With Swift 3, the way that parameter names are treated has changed. Now the first parameter will always be shown unless explicitly requested not to. This means that functions declarations should take that into account and no longer need to use long, descriptive names. 562 | 563 | ##### Like this: 564 | ```Swift 565 | func move(view: UIView, toFrame: CGRect) 566 | 567 | func preferredFont(forTextStyle: String) -> UIFont 568 | ``` 569 | 570 | ###### Not this: 571 | ```Swift 572 | func moveView(view: UIView, toFrame frame: CGRect) 573 | 574 | func preferredFontForTextStyle(style: String) -> UIFont 575 | ``` 576 | 577 | If you absolutely need to hide the first parameter name it is still possible by using an `_` for its external name, but this is not preferred. 578 | ```Swift 579 | func moveView(_ view: UIView, toFrame: CGRect) 580 | ``` 581 | 582 | **_Rationale:_** Function declarations should flow as a sentence in order to make them easier to understand and reason about. 583 | 584 | ### Naming 585 | 586 | Avoid needless repetition when naming functions. This is following the style of the core API changes in Swift 3. 587 | 588 | ##### Like this: 589 | ```Swift 590 | let blue = UIColor.blue 591 | let newText = oldText.append(attributedString) 592 | ``` 593 | 594 | ###### Not this: 595 | ```Swift 596 | let blue = UIColor.blueColor() 597 | let newText = oldText.appendAttributedString(attributedString) 598 | ``` 599 | 600 | ### Calling 601 | 602 | ... some specifications on calling functions 603 | 604 | - Avoid declaring large arguments inline 605 | - For functions with many arguments, specify each arg on a new line and the `)` on the final line 606 | - Use trailing closure syntax for simple functions 607 | - Avoid trailing closures at the end of functions with many arguments. (3+) 608 | 609 | ## Closures 610 | 611 | ### Closure Specifications 612 | 613 | It is preferable to associate a closure's type from the left hand side when possible. 614 | 615 | ##### Like this: 616 | ```Swift 617 | let layout: (UIView, UIView) -> Void = { (view1, view2) in 618 | view1.center = view2.center 619 | // ... 620 | } 621 | ``` 622 | 623 | ###### Not this: 624 | ```Swift 625 | let layout = { (view1: UIView, view2: UIView) in 626 | view1.center = view2.center 627 | // ... 628 | } 629 | ``` 630 | 631 | ### Void arguments/return types 632 | 633 | It is preferable to omit `Void` in closure arguments and return types whenever possible. 634 | 635 | ##### Like this: 636 | ```Swift 637 | let noArgNoReturnClosure = { doSomething() } // no arguments or return types, omit both 638 | let noArgClosure = { () -> Int in return getValue() } // void argument, use '()' 639 | let noReturnClosure = { (arg) in doSomething(with: arg) } // void return type, omit return type 640 | ``` 641 | 642 | ###### Not this: 643 | ```Swift 644 | let noArgNoReturnClosure = { (Void) -> Void in doSomething() } 645 | let noArgClosure = { (Void) -> Int in return getValue() } 646 | let noReturnClosure = { (arg) -> Void in doSomething(with: arg) } 647 | ``` 648 | **_Rationale:_** A `Void` return type can be inferred, thus it is unnecessarily verbose to include it 649 | 650 | When defining closure type, prefer `()` for parameters, and `Void` for return types. 651 | 652 | ##### Like this: 653 | ```Swift 654 | typealias NoArgNoReturnClosure = () -> Void 655 | typealias NoArgClosure = () -> Int 656 | typealias NoReturnClosure = Int -> Void 657 | ``` 658 | 659 | ###### Not this: 660 | ```Swift 661 | typealias NoArgNoReturnClosure = (Void) -> () 662 | typealias NoArgClosure = (Void) -> Int 663 | typealias NoReturnClosure = Int -> () 664 | ``` 665 | 666 | **_Rationale:_** `Void` is more readable than `()`, especially when wrapped in more parentheses. `() -> Void` is also the standard in Apple APIs and documentation. 667 | 668 | ### Shorthand 669 | 670 | Shorthand argument syntax should only be used in closures that can be understood in a few lines. In other situations, declaring a variable that helps identify the underlying value is preferred. 671 | 672 | ##### Like this: 673 | ```Swift 674 | doSomethingWithCompletion() { result in 675 | // do things with result 676 | switch result { 677 | // ... 678 | } 679 | } 680 | ``` 681 | 682 | ###### Not this: 683 | ```Swift 684 | doSomethingWithCompletion() { 685 | // do things with result 686 | switch $0 { 687 | // ... 688 | } 689 | } 690 | ``` 691 | 692 | Using shorthand syntax is preferable in situations where the arguments are well understood and can be expressed in a few lines. 693 | 694 | ```Swift 695 | let sortedNames = names.sort { $0 < $1 } 696 | ``` 697 | ### Trailing Closures 698 | 699 | Use trailing closure syntax only if there's a single closure expression parameter at the end of the argument list. 700 | 701 | ##### Like this: 702 | ```swift 703 | UIView.animateWithDuration(1.0) { 704 | self.myView.alpha = 0 705 | } 706 | ``` 707 | 708 | ###### Not this: 709 | ```swift 710 | UIView.animateWithDuration(1.0, animations: { 711 | self.myView.alpha = 0 712 | }) 713 | ``` 714 | 715 | ### Multiple Closures 716 | 717 | When a function takes multiple closures as arguments it can be difficult to read. To keep it clean, use a new line for each argument and avoid trailing closures. If you're not going to use the variable from the closure input, name it with an underscore `_`. 718 | 719 | ##### Like this: 720 | ```swift 721 | UIView.animateWithDuration( 722 | SomeTimeValue, 723 | animations: { 724 | // Do stuff 725 | }, 726 | completion: { _ in 727 | // Do stuff 728 | } 729 | ) 730 | ``` 731 | ###### Not this: 732 | ```swift 733 | UIView.animateWithDuration(SomeTimeValue, animations: { 734 | // Do stuff 735 | }) { complete in 736 | // Do stuff 737 | } 738 | ``` 739 | (Even though the default spacing and syntax from Xcode might do it this way) 740 | 741 | ### Referring to `self` 742 | 743 | When referring to `self` within a closure you must be careful to avoid creating a [strong reference cycle](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID56). Always use a capture list, such as `[weak self]` when it's necessary to use functions or properties outside of the closure. 744 | 745 | ##### Like this: 746 | ```swift 747 | lazy var someClosure: () -> String? = { [weak self] in 748 | guard let safeSelf = self else { return nil } 749 | return safeSelf.someFunction() 750 | } 751 | ``` 752 | 753 | ##### Not this: 754 | ```swift 755 | viewModel.someClosure { self in 756 | self.outsideFunction() 757 | } 758 | ``` 759 | 760 | **_Rationale_** If a closure holds onto a strong reference to a property being used within it there will be a strong reference cycle causing a memory leak. 761 | 762 | ### Should I use `unowned` or `weak`? 763 | 764 | * `weak` is always preferable as it creates an optional so that crashes are prevented. `unowned` is only useful when you are guaranteed that the value will never be `nil` within the closure. Since this creates the possibility for unsafe access it should be avoided. 765 | -------------------------------------------------------------------------------- /SwiftStyleSettings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | kRequireOpenBraceOnStructDeclarationLine 6 | 7 | kColonSpacingRuleInFunctionCall 8 | 0 9 | kRequireOpenBraceOnEnumDeclarationLine 10 | 11 | kGenericDeclarationSpacingRule 12 | 3 13 | kNumberOfEmptyLinesBetweenMethods 14 | 1 15 | kShouldSurroundLogicOperatorsWithSpaces 16 | 17 | kShouldEnumNameStartWithCapitalLetter 18 | 19 | kViolationsShouldBeErrors 20 | 21 | kRequireOpenBraceForIfStatement 22 | 23 | kShouldSurroundEqualsWithSpaces 24 | 25 | kRequireSpaceBeforeParanthesesInFuncCall 26 | 27 | kNumberOfEmptyLinesAtEndOfFile 28 | 1 29 | kRequireSpaceBeforeParameterParanthesesInOperatorFuncSignature 30 | 31 | kColonSpacingRuleInDictionary 32 | 1 33 | kColonSpacingRuleInVariableDeclaration 34 | 0 35 | kRequireOpenBraceForLoops 36 | 37 | kNumberOfEmptyLinesAboveMARK 38 | 1 39 | kShouldFuncNameStartWithCapitalLetter 40 | 41 | kShouldStructNameStartWithCapitalLetter 42 | 43 | kVariableSetterSpacingRule 44 | 3 45 | kRequireSpaceBeforeOpeningBrace 46 | 47 | kColonSpacingRuleInClassDeclaration 48 | 0 49 | kColonSpacingRuleInMethodSignature 50 | 0 51 | kReturnOperatorRuleInMethodSignature 52 | 1 53 | kNumberOfEmptyLinesBelowImport 54 | 1 55 | kRequireSpaceBeforeTypeSpecifier 56 | 57 | kRequireOpenBraceForSwitchStatement 58 | 59 | kRequireSpaceAfterCommas 60 | 61 | kShouldClassNameStartWithCapitalLetter 62 | 63 | kMathOperatorSpacingRule 64 | 1 65 | kRequireOpenBraceOnMethodSignatureLine 66 | 67 | kRequireSpaceBeforeParameterParanthesesInFuncSignature 68 | 69 | kShouldTypeAliasNameStartWithCapitalLetter 70 | 71 | kRequireOpenBraceOnClassDeclarationLine 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /intrepid-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntrepidPursuits/swift-style-guide/5a28415b2a2483adcf9022b75c6bd67a00b6d826/intrepid-logo.png -------------------------------------------------------------------------------- /mark-with-dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntrepidPursuits/swift-style-guide/5a28415b2a2483adcf9022b75c6bd67a00b6d826/mark-with-dash.png -------------------------------------------------------------------------------- /mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntrepidPursuits/swift-style-guide/5a28415b2a2483adcf9022b75c6bd67a00b6d826/mark.png --------------------------------------------------------------------------------