├── .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 | 
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 | 
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 | 
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
--------------------------------------------------------------------------------