;
51 | }
52 | }
53 | ```
54 |
55 | And if you don't have state or refs, prefer normal functions (not arrow functions) over classes:
56 |
57 | ```jsx
58 | // bad
59 | class Listing extends React.Component {
60 | render() {
61 | return
{this.props.hello}
;
62 | }
63 | }
64 |
65 | // bad (relying on function name inference is discouraged)
66 | const Listing = ({ hello }) => (
67 |
{hello}
68 | );
69 |
70 | // good
71 | function Listing({ hello }) {
72 | return
{hello}
;
73 | }
74 | ```
75 |
76 | ## Mixins
77 |
78 | - [Do not use mixins](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html).
79 |
80 | > Why? Mixins introduce implicit dependencies, cause name clashes, and cause snowballing complexity. Most use cases for mixins can be accomplished in better ways via components, higher-order components, or utility modules.
81 |
82 | ## Naming
83 |
84 | - **Extensions**: Use `.js` extension for React components.
85 | - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.js`.
86 | - **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md)
87 |
88 | ```jsx
89 | // bad
90 | import reservationCard from './ReservationCard';
91 |
92 | // good
93 | import ReservationCard from './ReservationCard';
94 |
95 | // bad
96 | const ReservationItem = ;
97 |
98 | // good
99 | const reservationItem = ;
100 | ```
101 |
102 | - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.js` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name:
103 |
104 | ```jsx
105 | // bad
106 | import Footer from './Footer/Footer';
107 |
108 | // bad
109 | import Footer from './Footer/index';
110 |
111 | // good
112 | import Footer from './Footer';
113 | ```
114 | - **Higher-order Component Naming**: Use a composite of the higher-order component's name and the passed-in component's name as the `displayName` on the generated component. For example, the higher-order component `withFoo()`, when passed a component `Bar` should produce a component with a `displayName` of `withFoo(Bar)`.
115 |
116 | > Why? A component's `displayName` may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening.
117 |
118 | ```jsx
119 | // bad
120 | export default function withFoo(WrappedComponent) {
121 | return function WithFoo(props) {
122 | return ;
123 | }
124 | }
125 |
126 | // good
127 | export default function withFoo(WrappedComponent) {
128 | function WithFoo(props) {
129 | return ;
130 | }
131 |
132 | const wrappedComponentName = WrappedComponent.displayName
133 | || WrappedComponent.name
134 | || 'Component';
135 |
136 | WithFoo.displayName = `withFoo(${wrappedComponentName})`;
137 | return WithFoo;
138 | }
139 | ```
140 |
141 | - **Props Naming**: Avoid using DOM component prop names for different purposes.
142 |
143 | > Why? People expect props like `style` and `className` to mean one specific thing. Varying this API for a subset of your app makes the code less readable and less maintainable, and may cause bugs.
144 |
145 | ```jsx
146 | // bad
147 |
148 |
149 | // good
150 |
151 | ```
152 |
153 | ## Declaration
154 |
155 | - Do not use `displayName` for naming components. Instead, name the component by reference.
156 |
157 | ```jsx
158 | // bad
159 | export default React.createClass({
160 | displayName: 'ReservationCard',
161 | // stuff goes here
162 | });
163 |
164 | // good
165 | export default class ReservationCard extends React.Component {
166 | }
167 | ```
168 |
169 | ## Alignment
170 |
171 | - Follow these alignment styles for JSX syntax. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md)
172 |
173 | ```jsx
174 | // bad
175 |
177 |
178 | // good
179 |
183 |
184 | // if props fit in one line then keep it on the same line
185 |
186 |
187 | // children get indented normally
188 |
192 |
193 |
194 | ```
195 |
196 | ## Quotes
197 |
198 | - Always use double quotes (`"`) for JSX attributes, but single quotes (`'`) for all other JS. eslint: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes)
199 |
200 | > Why? Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention.
201 |
202 | ```jsx
203 | // bad
204 |
205 |
206 | // good
207 |
208 |
209 | // bad
210 |
211 |
212 | // good
213 |
214 | ```
215 |
216 | ## Spacing
217 |
218 | - Always include a single space in your self-closing tag. eslint: [`no-multi-spaces`](http://eslint.org/docs/rules/no-multi-spaces), [`react/jsx-space-before-closing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md)
219 |
220 | ```jsx
221 | // bad
222 |
223 |
224 | // very bad
225 |
226 |
227 | // bad
228 |
230 |
231 | // good
232 |
233 | ```
234 |
235 | - Do not pad JSX curly braces with spaces. eslint: [`react/jsx-curly-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md)
236 |
237 | ```jsx
238 | // bad
239 |
240 |
241 | // good
242 |
243 | ```
244 |
245 | ## Props
246 |
247 | - Always use camelCase for prop names.
248 |
249 | ```jsx
250 | // bad
251 |
255 |
256 | // good
257 |
261 | ```
262 |
263 | - Omit the value of the prop when it is explicitly `true`. eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md)
264 |
265 | ```jsx
266 | // bad
267 |
270 |
271 | // good
272 |
275 | ```
276 |
277 | - Always include an `alt` prop on `` tags. If the image is presentational, `alt` can be an empty string or the `` must have `role="presentation"`. eslint: [`jsx-a11y/img-has-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-has-alt.md)
278 |
279 | ```jsx
280 | // bad
281 |
282 |
283 | // good
284 |
285 |
286 | // good
287 |
288 |
289 | // good
290 |
291 | ```
292 |
293 | - Do not use words like "image", "photo", or "picture" in `` `alt` props. eslint: [`jsx-a11y/img-redundant-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md)
294 |
295 | > Why? Screenreaders already announce `img` elements as images, so there is no need to include this information in the alt text.
296 |
297 | ```jsx
298 | // bad
299 |
300 |
301 | // good
302 |
303 | ```
304 |
305 | - Use only valid, non-abstract [ARIA roles](https://www.w3.org/TR/wai-aria/roles#role_definitions). eslint: [`jsx-a11y/aria-role`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md)
306 |
307 | ```jsx
308 | // bad - not an ARIA role
309 |
310 |
311 | // bad - abstract ARIA role
312 |
313 |
314 | // good
315 |
316 | ```
317 |
318 | - Do not use `accessKey` on elements. eslint: [`jsx-a11y/no-access-key`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md)
319 |
320 | > Why? Inconsistencies between keyboard shortcuts and keyboard commands used by people using screenreaders and keyboards complicate accessibility.
321 |
322 | ```jsx
323 | // bad
324 |
325 |
326 | // good
327 |
328 | ```
329 |
330 | - Avoid using an array index as `key` prop, prefer a unique ID. ([why?](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318))
331 |
332 | ```jsx
333 | // bad
334 | {todos.map((todo, index) =>
335 |
339 | )}
340 |
341 | // good
342 | {todos.map(todo => (
343 |
347 | ))}
348 | ```
349 |
350 | - Always define explicit defaultProps for all non-required props.
351 |
352 | > Why? propTypes are a form of documentation, and providing defaultProps means the reader of your code doesn’t have to assume as much. In addition, it can mean that your code can omit certain type checks.
353 |
354 | ```jsx
355 | // bad
356 | function SFC({ foo, bar, children }) {
357 | return
466 | );
467 | }
468 | ```
469 |
470 | - Bind event handlers for the render method in the constructor. eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)
471 |
472 | > Why? A bind call in the render path creates a brand new function on every single render.
473 |
474 | ```jsx
475 | // bad
476 | class extends React.Component {
477 | onClickDiv() {
478 | // do stuff
479 | }
480 |
481 | render() {
482 | return
483 | }
484 | }
485 |
486 | // good
487 | class extends React.Component {
488 | constructor(props) {
489 | super(props);
490 |
491 | this.onClickDiv = this.onClickDiv.bind(this);
492 | }
493 |
494 | onClickDiv() {
495 | // do stuff
496 | }
497 |
498 | render() {
499 | return
500 | }
501 | }
502 | ```
503 |
504 | - Do not use underscore prefix for internal methods of a React component.
505 | > Why? Underscore prefixes are sometimes used as a convention in other languages to denote privacy. But, unlike those languages, there is no native support for privacy in JavaScript, everything is public. Regardless of your intentions, adding underscore prefixes to your properties does not actually make them private, and any property (underscore-prefixed or not) should be treated as being public. See issues [#1024](https://github.com/airbnb/javascript/issues/1024), and [#490](https://github.com/airbnb/javascript/issues/490) for a more in-depth discussion.
506 |
507 | ```jsx
508 | // bad
509 | React.createClass({
510 | _onClickSubmit() {
511 | // do stuff
512 | },
513 |
514 | // other stuff
515 | });
516 |
517 | // good
518 | class extends React.Component {
519 | onClickSubmit() {
520 | // do stuff
521 | }
522 |
523 | // other stuff
524 | }
525 | ```
526 |
527 | - Be sure to return a value in your `render` methods. eslint: [`react/require-render-return`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md)
528 |
529 | ```jsx
530 | // bad
531 | render() {
532 | ();
533 | }
534 |
535 | // good
536 | render() {
537 | return ();
538 | }
539 | ```
540 |
541 | ## Ordering
542 |
543 | - Ordering for `class extends React.Component`:
544 |
545 | 1. optional `static` methods
546 | 1. `constructor`
547 | 1. `getChildContext`
548 | 1. `componentWillMount`
549 | 1. `componentDidMount`
550 | 1. `componentWillReceiveProps`
551 | 1. `shouldComponentUpdate`
552 | 1. `componentWillUpdate`
553 | 1. `componentDidUpdate`
554 | 1. `componentWillUnmount`
555 | 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
556 | 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
557 | 1. *optional render methods* like `renderNavigation()` or `renderProfilePicture()`
558 | 1. `render`
559 |
560 | - How to define `propTypes`, `defaultProps`, `contextTypes`, etc...
561 |
562 | ```jsx
563 | import React, { PropTypes } from 'react';
564 |
565 | class Link extends React.Component {
566 | static methodsAreOk() {
567 | return true;
568 | }
569 |
570 | render() {
571 | return {this.props.text}
572 | }
573 | }
574 |
575 | Link.propTypes = {
576 | id: PropTypes.number.isRequired,
577 | url: PropTypes.string.isRequired,
578 | text: PropTypes.string
579 | };
580 |
581 | Link.defaultProps = {
582 | text: 'Hello World'
583 | };
584 |
585 | export default Link;
586 | ```
587 |
588 | - Ordering for `React.createClass`: eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md)
589 |
590 | 1. `displayName`
591 | 1. `propTypes`
592 | 1. `contextTypes`
593 | 1. `childContextTypes`
594 | 1. `mixins`
595 | 1. `statics`
596 | 1. `defaultProps`
597 | 1. `getDefaultProps`
598 | 1. `getInitialState`
599 | 1. `getChildContext`
600 | 1. `componentWillMount`
601 | 1. `componentDidMount`
602 | 1. `componentWillReceiveProps`
603 | 1. `shouldComponentUpdate`
604 | 1. `componentWillUpdate`
605 | 1. `componentDidUpdate`
606 | 1. `componentWillUnmount`
607 | 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
608 | 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
609 | 1. *optional render methods* like `renderNavigation()` or `renderProfilePicture()`
610 | 1. `render`
611 |
612 | ## `isMounted`
613 |
614 | - Do not use `isMounted`. eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md)
615 |
616 | > Why? [`isMounted` is an anti-pattern][anti-pattern], is not available when using ES6 classes, and is on its way to being officially deprecated.
617 |
618 | [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
619 |
620 | ## Translation
621 |
622 | This JSX/React style guide is also available in other languages:
623 |
624 | -  **Chinese (Simplified)**: [JasonBoy/javascript](https://github.com/JasonBoy/javascript/tree/master/react)
625 | -  **Polish**: [pietraszekl/javascript](https://github.com/pietraszekl/javascript/tree/master/react)
626 | -  **Korean**: [apple77y/javascript](https://github.com/apple77y/javascript/tree/master/react)
627 | -  **Portuguese**: [ronal2do/javascript](https://github.com/ronal2do/airbnb-react-styleguide)
628 | -  **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide/tree/master/react)
629 | -  **Español**: [agrcrobles/javascript](https://github.com/agrcrobles/javascript/tree/master/react)
630 | -  **Ukrainian**: [ivanzusko/javascript](https://github.com/ivanzusko/javascript/tree/master/react)
631 |
632 | **[⬆ back to top](#table-of-contents)**
633 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # MakingSense code style guides
2 |
3 | This repository contains several style guides taken and adapted from a variety
4 | of sources.
5 |
6 | Like any style guide, this will change over time, and we encourage everyone to
7 | provide suggestions.
8 |
9 | ## Code Style guides
10 |
11 | - [Javascript ES6](Javascript(ES6)/README.md)
12 | - [Javascript ES5](Javascript(ES5)/README.md)
13 | - [NodeJs](NodeJs/Readme.md)
14 | - [Java](Java/README.md)
15 | - [Angular 1.x](Angular(1.x)/README.md)
16 | - [React](React/README.md)
17 | - [Swift](Swift/Readme.md)
18 | - [C#](CSharp/README.md)
19 |
--------------------------------------------------------------------------------
/Swift/Readme.md:
--------------------------------------------------------------------------------
1 | # MakingSense Swift Style Guide
2 |
3 | Forked from [raywenderlich Swift styleguide](https://github.com/raywenderlich/swift-style-guide), slightly modified to fit MakingSense conventions.
4 |
5 | ## Table of Contents
6 |
7 | * [Correctness](#correctness)
8 | * [Naming](#naming)
9 | * [Prose](#prose)
10 | * [Delegates](#delegates)
11 | * [Use Type Inferred Context](#use-type-inferred-context)
12 | * [Generics](#generics)
13 | * [Class Prefixes](#class-prefixes)
14 | * [Language](#language)
15 | * [Code Organization](#code-organization)
16 | * [Protocol Conformance](#protocol-conformance)
17 | * [Unused Code](#unused-code)
18 | * [Minimal Imports](#minimal-imports)
19 | * [Spacing](#spacing)
20 | * [Comments](#comments)
21 | * [Classes and Structures](#classes-and-structures)
22 | * [Use of Self](#use-of-self)
23 | * [Protocol Conformance](#protocol-conformance)
24 | * [Computed Properties](#computed-properties)
25 | * [Final](#final)
26 | * [Function Declarations](#function-declarations)
27 | * [Closure Expressions](#closure-expressions)
28 | * [Types](#types)
29 | * [Constants](#constants)
30 | * [Static Methods and Variable Type Properties](#static-methods-and-variable-type-properties)
31 | * [Optionals](#optionals)
32 | * [Lazy Initialization](#lazy-initialization)
33 | * [Type Inference](#type-inference)
34 | * [Syntactic Sugar](#syntactic-sugar)
35 | * [Functions vs Methods](#functions-vs-methods)
36 | * [Memory Management](#memory-management)
37 | * [Extending Lifetime](#extending-lifetime)
38 | * [Access Control](#access-control)
39 | * [Control Flow](#control-flow)
40 | * [Golden Path](#golden-path)
41 | * [Failing Guards](#failing-guards)
42 | * [Semicolons](#semicolons)
43 | * [Parentheses](#parentheses)
44 | * [Organization and Bundle Identifier](#organization-and-bundle-identifier)
45 | * [Copyright Statement](#copyright-statement)
46 | * [Smiley Face](#smiley-face)
47 | * [References](#references)
48 |
49 |
50 | ## Correctness
51 |
52 | Strive to make your code compile without warnings. This rule informs many style decisions such as using `#selector` types instead of string literals.
53 |
54 | ## Naming
55 |
56 | Descriptive and consistent naming makes software easier to read and understand. Use the Swift naming conventions described in the [API Design Guidelines](https://swift.org/documentation/api-design-guidelines/). Some key takeaways include:
57 |
58 | - striving for clarity at the call site
59 | - prioritizing clarity over brevity
60 | - using camel case (not snake case)
61 | - using uppercase for types (and protocols), lowercase for everything else
62 | - including all needed words while omitting needless words
63 | - using names based on roles, not types
64 | - sometimes compensating for weak type information
65 | - striving for fluent usage
66 | - beginning factory methods with `make`
67 | - naming methods for their side effects
68 | - verb methods follow the -ed, -ing rule for the non-mutating version
69 | - noun methods follow the formX rule for the non-mutating version
70 | - boolean types should read like assertions
71 | - protocols that describe _what something is_ should read as nouns
72 | - protocols that describe _a capability_ should end in _-able_ or _-ible_
73 | - using terms that don't surprise experts or confuse beginners
74 | - generally avoiding abbreviations
75 | - using precedent for names
76 | - preferring methods and properties to free functions
77 | - casing acronyms and initialisms uniformly up or down
78 | - giving the same base name to methods that share the same meaning
79 | - avoiding overloads on return type
80 | - choosing good parameter names that serve as documentation
81 | - labeling closure and tuple parameters
82 | - taking advantage of default parameters
83 |
84 | ### Prose
85 |
86 | When referring to methods in prose, being unambiguous is critical. To refer to a method name, use the simplest form possible.
87 |
88 | 1. Write the method name with no parameters. **Example:** Next, you need to call the method `addTarget`.
89 | 2. Write the method name with argument labels. **Example:** Next, you need to call the method `addTarget(_:action:)`.
90 | 3. Write the full method name with argument labels and types. **Example:** Next, you need to call the method `addTarget(_: Any?, action: Selector?)`.
91 |
92 | For the above example using `UIGestureRecognizer`, 1 is unambiguous and preferred.
93 |
94 | **Pro Tip:** You can use Xcode's jump bar to lookup methods with argument labels.
95 |
96 | 
97 |
98 |
99 | ### Class Prefixes
100 |
101 | Swift types are automatically namespaced by the module that contains them and you should not add a class prefix such as RW. If two names from different modules collide you can disambiguate by prefixing the type name with the module name. However, only specify the module name when there is possibility for confusion which should be rare.
102 |
103 | ```swift
104 | import SomeModule
105 |
106 | let myClass = MyModule.UsefulClass()
107 | ```
108 |
109 | ### Delegates
110 |
111 | When creating custom delegate methods, an unnamed first parameter should be the delegate source. (UIKit contains numerous examples of this.)
112 |
113 | **Preferred:**
114 | ```swift
115 | func namePickerView(_ namePickerView: NamePickerView, didSelectName name: String)
116 | func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
117 | ```
118 |
119 | **Not Preferred:**
120 | ```swift
121 | func didSelectName(namePicker: NamePickerViewController, name: String)
122 | func namePickerShouldReload() -> Bool
123 | ```
124 |
125 | ### Use Type Inferred Context
126 |
127 | Use compiler inferred context to write shorter, clear code. (Also see [Type Inference](#type-inference).)
128 |
129 | **Preferred:**
130 | ```swift
131 | let selector = #selector(viewDidLoad)
132 | view.backgroundColor = .red
133 | let toView = context.view(forKey: .to)
134 | let view = UIView(frame: .zero)
135 | ```
136 |
137 | **Not Preferred:**
138 | ```swift
139 | let selector = #selector(ViewController.viewDidLoad)
140 | view.backgroundColor = UIColor.red
141 | let toView = context.view(forKey: UITransitionContextViewKey.to)
142 | let view = UIView(frame: CGRect.zero)
143 | ```
144 |
145 | ### Generics
146 |
147 | Generic type parameters should be descriptive, upper camel case names. When a type name doesn't have a meaningful relationship or role, use a traditional single uppercase letter such as `T`, `U`, or `V`.
148 |
149 | **Preferred:**
150 | ```swift
151 | func write(to target: inout Target)
152 | func swap(_ a: inout T, _ b: inout T)
153 | ```
154 |
155 | **Not Preferred:**
156 | ```swift
157 | func write(to target: inout target)
158 | func swap(_ a: inout Thing, _ b: inout Thing)
159 | ```
160 |
161 | ### Language
162 |
163 | Use US English spelling to match Apple's API.
164 |
165 | **Preferred:**
166 | ```swift
167 | let color = "red"
168 | ```
169 |
170 | **Not Preferred:**
171 | ```swift
172 | let colour = "red"
173 | ```
174 |
175 | ## Code Organization
176 |
177 | Use extensions to organize your code into logical blocks of functionality. Each extension should be set off with a `// MARK: -` comment to keep things well-organized.
178 |
179 | ### Protocol Conformance
180 |
181 | In particular, when adding protocol conformance to a model, avoid adding a separate extension for the protocol methods. With this approach, it's easier to quickly identity the responsibilities of the class.
182 |
183 | **Preferred:**
184 | ```swift
185 | class MyViewController: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
186 | // all methods
187 | }
188 | ```
189 |
190 | **Not Preferred:**
191 | ```swift
192 |
193 | class MyViewController: UIViewController {
194 | // class stuff here
195 | }
196 |
197 | // MARK: - UITableViewDataSource
198 | extension MyViewController: UITableViewDataSource {
199 | // table view data source methods
200 | }
201 |
202 | // MARK: - UIScrollViewDelegate
203 | extension MyViewController: UIScrollViewDelegate {
204 | // scroll view delegate methods
205 | }
206 | ```
207 |
208 | For UIKit view controllers, consider grouping lifecycle, custom accessors, and IBAction in separate class extensions.
209 |
210 | ### Unused Code
211 |
212 | Unused (dead) code, including Xcode template code and placeholder comments should be removed. An exception is when your tutorial or book instructs the user to use the commented code.
213 |
214 | Aspirational methods not directly associated with the tutorial whose implementation simply calls the superclass should also be removed. This includes any empty/unused UIApplicationDelegate methods.
215 |
216 | **Preferred:**
217 | ```swift
218 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
219 | return Database.contacts.count
220 | }
221 | ```
222 |
223 | **Not Preferred:**
224 | ```swift
225 | override func didReceiveMemoryWarning() {
226 | super.didReceiveMemoryWarning()
227 | // Dispose of any resources that can be recreated.
228 | }
229 |
230 | override func numberOfSections(in tableView: UITableView) -> Int {
231 | // #warning Incomplete implementation, return the number of sections
232 | return 1
233 | }
234 |
235 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
236 | // #warning Incomplete implementation, return the number of rows
237 | return Database.contacts.count
238 | }
239 |
240 | ```
241 | ### Minimal Imports
242 |
243 | Keep imports minimal. For example, don't import `UIKit` when importing `Foundation` will suffice.
244 |
245 | ## Spacing
246 |
247 | * Indent using 4 spaces rather than tabs. Be sure to set this preference in Xcode and in the Project settings as shown below:
248 |
249 | 
250 |
251 | * Method braces and other braces (`if`/`else`/`switch`/`while` etc.) always open on the same line as the statement but close on a new line.
252 | * Tip: You can re-indent by selecting some code (or ⌘A to select all) and then Control-I (or Editor\Structure\Re-Indent in the menu). Some of the Xcode template code will have 4-space tabs hard coded, so this is a good way to fix that.
253 |
254 | **Preferred:**
255 | ```swift
256 | if user.isHappy {
257 | // Do something
258 | } else {
259 | // Do something else
260 | }
261 | ```
262 |
263 | **Not Preferred:**
264 | ```swift
265 | if user.isHappy
266 | {
267 | // Do something
268 | }
269 | else {
270 | // Do something else
271 | }
272 | ```
273 |
274 | * There should be exactly one blank line between methods to aid in visual clarity and organization. Whitespace within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods.
275 |
276 | * Colons always have no space on the left and one space on the right. Exceptions are the ternary operator `? :`, empty dictionary `[:]` and `#selector` syntax for unnamed parameters `(_:)`.
277 |
278 | **Preferred:**
279 | ```swift
280 | class TestDatabase: Database {
281 | var data: [String: CGFloat] = ["A": 1.2, "B": 3.2]
282 | }
283 | ```
284 |
285 | **Not Preferred:**
286 | ```swift
287 | class TestDatabase : Database {
288 | var data :[String:CGFloat] = ["A" : 1.2, "B":3.2]
289 | }
290 | ```
291 |
292 | * Long lines should be wrapped at around 120 characters. A hard limit is intentionally not specified.
293 |
294 | * Avoid trailing whitespaces at the ends of lines.
295 |
296 | * Add a single newline character at the end of each file.
297 |
298 | ## Comments
299 |
300 | When they are needed, use comments to explain **why** a particular piece of code does something. Comments must be kept up-to-date or deleted.
301 |
302 | Avoid block comments inline with code, as the code should be as self-documenting as possible. *Exception: This does not apply to those comments used to generate documentation.*
303 |
304 |
305 | ## Classes and Structures
306 |
307 | ### Which one to use?
308 |
309 | Remember, structs have [value semantics](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_144). Use structs for things that do not have an identity. An array that contains [a, b, c] is really the same as another array that contains [a, b, c] and they are completely interchangeable. It doesn't matter whether you use the first array or the second, because they represent the exact same thing. That's why arrays are structs.
310 |
311 | Classes have [reference semantics](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_145). Use classes for things that do have an identity or a specific life cycle. You would model a person as a class because two person objects are two different things. Just because two people have the same name and birthdate, doesn't mean they are the same person. But the person's birthdate would be a struct because a date of 3 March 1950 is the same as any other date object for 3 March 1950. The date itself doesn't have an identity.
312 |
313 | Sometimes, things should be structs but need to conform to `AnyObject` or are historically modeled as classes already (`NSDate`, `NSSet`). Try to follow these guidelines as closely as possible.
314 |
315 | ### Example definition
316 |
317 | Here's an example of a well-styled class definition:
318 |
319 | ```swift
320 | class Circle: Shape {
321 | var x: Int, y: Int
322 | var radius: Double
323 | var diameter: Double {
324 | get {
325 | return radius * 2
326 | }
327 | set {
328 | radius = newValue / 2
329 | }
330 | }
331 |
332 | init(x: Int, y: Int, radius: Double) {
333 | self.x = x
334 | self.y = y
335 | self.radius = radius
336 | }
337 |
338 | convenience init(x: Int, y: Int, diameter: Double) {
339 | self.init(x: x, y: y, radius: diameter / 2)
340 | }
341 |
342 | override func area() -> Double {
343 | return Double.pi * radius * radius
344 | }
345 | }
346 |
347 | extension Circle: CustomStringConvertible {
348 | var description: String {
349 | return "center = \(centerString) area = \(area())"
350 | }
351 | private var centerString: String {
352 | return "(\(x),\(y))"
353 | }
354 | }
355 | ```
356 |
357 | The example above demonstrates the following style guidelines:
358 |
359 | + Specify types for properties, variables, constants, argument declarations and other statements with a space after the colon but not before, e.g. `x: Int`, and `Circle: Shape`.
360 | + Define multiple variables and structures on a single line if they share a common purpose / context.
361 | + Indent getter and setter definitions and property observers.
362 | + Don't add modifiers such as `internal` when they're already the default. Similarly, don't repeat the access modifier when overriding a method.
363 | + Organize extra functionality (e.g. printing) in extensions.
364 | + Hide non-shared, implementation details such as `centerString` inside the extension using `private` access control.
365 |
366 | ### Use of Self
367 |
368 | For conciseness, avoid using `self` since Swift does not require it to access an object's properties or invoke its methods.
369 |
370 | Use self only when required by the compiler (in `@escaping` closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without `self` then omit it.
371 |
372 |
373 | ### Computed Properties
374 |
375 | For conciseness, if a computed property is read-only, omit the get clause. The get clause is required only when a set clause is provided.
376 |
377 | **Preferred:**
378 | ```swift
379 | var diameter: Double {
380 | return radius * 2
381 | }
382 | ```
383 |
384 | **Not Preferred:**
385 | ```swift
386 | var diameter: Double {
387 | get {
388 | return radius * 2
389 | }
390 | }
391 | ```
392 |
393 | ### Final
394 |
395 | Marking classes or members as `final` in tutorials can distract from the main topic and is not required. Nevertheless, use of `final` can sometimes clarify your intent and is worth the cost. In the below example, `Box` has a particular purpose and customization in a derived class is not intended. Marking it `final` makes that clear.
396 |
397 | ```swift
398 | // Turn any generic type into a reference type using this Box class.
399 | final class Box {
400 | let value: T
401 | init(_ value: T) {
402 | self.value = value
403 | }
404 | }
405 | ```
406 |
407 | ## Function Declarations
408 |
409 | Keep short function declarations on one line including the opening brace:
410 |
411 | ```swift
412 | func reticulateSplines(spline: [Double]) -> Bool {
413 | // reticulate code goes here
414 | }
415 | ```
416 |
417 | For functions with long signatures, add line breaks at appropriate points and add an extra indent on subsequent lines:
418 |
419 | ```swift
420 | func reticulateSplines(spline: [Double], adjustmentFactor: Double,
421 | translateConstant: Int, comment: String) -> Bool {
422 | // reticulate code goes here
423 | }
424 | ```
425 |
426 | ## Closure Expressions
427 |
428 | Use trailing closure syntax only if there's a single closure expression parameter at the end of the argument list. Give the closure parameters descriptive names.
429 |
430 | **Preferred:**
431 | ```swift
432 | UIView.animate(withDuration: 1.0) {
433 | self.myView.alpha = 0
434 | }
435 |
436 | UIView.animate(withDuration: 1.0, animations: {
437 | self.myView.alpha = 0
438 | }, completion: { finished in
439 | self.myView.removeFromSuperview()
440 | })
441 | ```
442 |
443 | **Not Preferred:**
444 | ```swift
445 | UIView.animate(withDuration: 1.0, animations: {
446 | self.myView.alpha = 0
447 | })
448 |
449 | UIView.animate(withDuration: 1.0, animations: {
450 | self.myView.alpha = 0
451 | }) { f in
452 | self.myView.removeFromSuperview()
453 | }
454 | ```
455 |
456 | For single-expression closures where the context is clear, use implicit returns:
457 |
458 | ```swift
459 | attendeeList.sort { a, b in
460 | a > b
461 | }
462 | ```
463 |
464 | Chained methods using trailing closures should be clear and easy to read in context. Decisions on spacing, line breaks, and when to use named versus anonymous arguments is left to the discretion of the author. Examples:
465 |
466 | ```swift
467 | let value = numbers.map { $0 * 2 }.filter { $0 % 3 == 0 }.index(of: 90)
468 |
469 | let value = numbers
470 | .map {$0 * 2}
471 | .filter {$0 > 50}
472 | .map {$0 + 10}
473 | ```
474 |
475 | ## Types
476 |
477 | Always use Swift's native types when available. Swift offers bridging to Objective-C so you can still use the full set of methods as needed.
478 |
479 | **Preferred:**
480 | ```swift
481 | let width = 120.0 // Double
482 | let widthString = (width as NSNumber).stringValue // String
483 | ```
484 |
485 | **Not Preferred:**
486 | ```swift
487 | let width: NSNumber = 120.0 // NSNumber
488 | let widthString: NSString = width.stringValue // NSString
489 | ```
490 |
491 | In Sprite Kit code, use `CGFloat` if it makes the code more succinct by avoiding too many conversions.
492 |
493 | ### Constants
494 |
495 | Constants are defined using the `let` keyword, and variables with the `var` keyword. Always use `let` instead of `var` if the value of the variable will not change.
496 |
497 | **Tip:** A good technique is to define everything using `let` and only change it to `var` if the compiler complains!
498 |
499 | You can define constants on a type rather than on an instance of that type using type properties. To declare a type property as a constant simply use `static let`. Type properties declared in this way are generally preferred over global constants because they are easier to distinguish from instance properties. Example:
500 |
501 | **Preferred:**
502 | ```swift
503 | enum Math {
504 | static let e = 2.718281828459045235360287
505 | static let root2 = 1.41421356237309504880168872
506 | }
507 |
508 | let hypotenuse = side * Math.root2
509 |
510 | ```
511 | **Note:** The advantage of using a case-less enumeration is that it can't accidentally be instantiated and works as a pure namespace.
512 |
513 | **Not Preferred:**
514 | ```swift
515 | let e = 2.718281828459045235360287 // pollutes global namespace
516 | let root2 = 1.41421356237309504880168872
517 |
518 | let hypotenuse = side * root2 // what is root2?
519 | ```
520 |
521 | ### Static Methods and Variable Type Properties
522 |
523 | Static methods and type properties work similarly to global functions and global variables and should be used sparingly. They are useful when functionality is scoped to a particular type or when Objective-C interoperability is required.
524 |
525 | ### Optionals
526 |
527 | Declare variables and function return types as optional with `?` where a nil value is acceptable.
528 |
529 | Use implicitly unwrapped types declared with `!` only for instance variables that you know will be initialized later before use, such as subviews that will be set up in `viewDidLoad`.
530 |
531 | When accessing an optional value, use optional chaining if the value is only accessed once or if there are many optionals in the chain:
532 |
533 | ```swift
534 | self.textContainer?.textLabel?.setNeedsDisplay()
535 | ```
536 |
537 | Use optional binding when it's more convenient to unwrap once and perform multiple operations:
538 |
539 | ```swift
540 | if let textContainer = self.textContainer {
541 | // do many things with textContainer
542 | }
543 | ```
544 |
545 | When naming optional variables and properties, avoid naming them like `optionalString` or `maybeView` since their optional-ness is already in the type declaration.
546 |
547 | For optional binding, shadow the original name when appropriate rather than using names like `unwrappedView` or `actualLabel`.
548 |
549 | **Preferred:**
550 | ```swift
551 | var subview: UIView?
552 | var volume: Double?
553 |
554 | // later on...
555 | if let subview = subview, let volume = volume {
556 | // do something with unwrapped subview and volume
557 | }
558 | ```
559 |
560 | **Not Preferred:**
561 | ```swift
562 | var optionalSubview: UIView?
563 | var volume: Double?
564 |
565 | if let unwrappedSubview = optionalSubview {
566 | if let realVolume = volume {
567 | // do something with unwrappedSubview and realVolume
568 | }
569 | }
570 | ```
571 |
572 | ### Type Inference
573 |
574 | Prefer compact code and let the compiler infer the type for constants or variables of single instances. Type inference is also appropriate for small (non-empty) arrays and dictionaries. When required, specify the specific type such as `CGFloat` or `Int16`.
575 |
576 | **Preferred:**
577 | ```swift
578 | let message = "Click the button"
579 | let currentBounds = computeViewBounds()
580 | var names = ["Mic", "Sam", "Christine"]
581 | let maximumWidth: CGFloat = 106.5
582 | ```
583 |
584 | **Not Preferred:**
585 | ```swift
586 | let message: String = "Click the button"
587 | let currentBounds: CGRect = computeViewBounds()
588 | let names = [String]()
589 | ```
590 |
591 | #### Type Annotation for Empty Arrays and Dictionaries
592 |
593 | For empty arrays and dictionaries, use type annotation. (For an array or dictionary assigned to a large, multi-line literal, use type annotation.)
594 |
595 | **Preferred:**
596 | ```swift
597 | var names: [String] = []
598 | var lookup: [String: Int] = [:]
599 | ```
600 |
601 | **Not Preferred:**
602 | ```swift
603 | var names = [String]()
604 | var lookup = [String: Int]()
605 | ```
606 |
607 | **NOTE**: Following this guideline means picking descriptive names is even more important than before.
608 |
609 |
610 | ### Syntactic Sugar
611 |
612 | Prefer the shortcut versions of type declarations over the full generics syntax.
613 |
614 | **Preferred:**
615 | ```swift
616 | var deviceModels: [String]
617 | var employees: [Int: String]
618 | var faxNumber: Int?
619 | ```
620 |
621 | **Not Preferred:**
622 | ```swift
623 | var deviceModels: Array
624 | var employees: Dictionary
625 | var faxNumber: Optional
626 | ```
627 |
628 | ## Functions vs Methods
629 |
630 | Free functions, which aren't 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.
631 |
632 | Free functions are most appropriate when they aren't associated with any particular type or instance.
633 |
634 | **Preferred**
635 | ```swift
636 | let sorted = items.mergeSorted() // easily discoverable
637 | rocket.launch() // acts on the model
638 | ```
639 |
640 | **Not Preferred**
641 | ```swift
642 | let sorted = mergeSort(items) // hard to discover
643 | launch(&rocket)
644 | ```
645 |
646 | **Free Function Exceptions**
647 | ```swift
648 | let tuples = zip(a, b) // feels natural as a free function (symmetry)
649 | let value = max(x, y, z) // another free function that feels natural
650 | ```
651 |
652 | ## Memory Management
653 |
654 | Code (even non-production, tutorial demo code) should not create reference cycles. Analyze your object graph and prevent strong cycles with `weak` and `unowned` references. Alternatively, use value types (`struct`, `enum`) to prevent cycles altogether.
655 |
656 | ### Extending object lifetime
657 |
658 | Extend object lifetime using the `[weak self]` and `guard let strongSelf = self else { return }` idiom. `[weak self]` is preferred to `[unowned self]` where it is not immediately obvious that `self` outlives the closure. Explicitly extending lifetime is preferred to optional unwrapping.
659 |
660 | **Preferred**
661 | ```swift
662 | resource.request().onComplete { [weak self] response in
663 | guard let strongSelf = self else {
664 | return
665 | }
666 | let model = strongSelf.updateModel(response)
667 | strongSelf.updateUI(model)
668 | }
669 | ```
670 |
671 | **Not Preferred**
672 | ```swift
673 | // might crash if self is released before response returns
674 | resource.request().onComplete { [unowned self] response in
675 | let model = self.updateModel(response)
676 | self.updateUI(model)
677 | }
678 | ```
679 |
680 | **Not Preferred**
681 | ```swift
682 | // deallocate could happen between updating the model and updating UI
683 | resource.request().onComplete { [weak self] response in
684 | let model = self?.updateModel(response)
685 | self?.updateUI(model)
686 | }
687 | ```
688 |
689 | ## Access Control
690 |
691 | Full access control annotation in tutorials can distract from the main topic and is not required. Using `private` and `fileprivate` appropriately, however, adds clarity and promotes encapsulation. Prefer `private` to `fileprivate` when possible. Using extensions may require you to use `fileprivate`.
692 |
693 | Only explicitly use `open`, `public`, and `internal` when you require a full access control specification.
694 |
695 | Use access control as the leading property specifier. The only things that should come before access control are the `static` specifier or attributes such as `@IBAction`, `@IBOutlet` and `@discardableResult`.
696 |
697 | **Preferred:**
698 | ```swift
699 | private let message = "Great Scott!"
700 |
701 | class TimeMachine {
702 | fileprivate dynamic lazy var fluxCapacitor = FluxCapacitor()
703 | }
704 | ```
705 |
706 | **Not Preferred:**
707 | ```swift
708 | fileprivate let message = "Great Scott!"
709 |
710 | class TimeMachine {
711 | lazy dynamic fileprivate var fluxCapacitor = FluxCapacitor()
712 | }
713 | ```
714 |
715 | ## Control Flow
716 |
717 | Prefer the `for-in` style of `for` loop over the `while-condition-increment` style.
718 |
719 | **Preferred:**
720 | ```swift
721 | for _ in 0..<3 {
722 | print("Hello three times")
723 | }
724 |
725 | for (index, person) in attendeeList.enumerated() {
726 | print("\(person) is at position #\(index)")
727 | }
728 |
729 | for index in stride(from: 0, to: items.count, by: 2) {
730 | print(index)
731 | }
732 |
733 | for index in (0...3).reversed() {
734 | print(index)
735 | }
736 | ```
737 |
738 | **Not Preferred:**
739 | ```swift
740 | var i = 0
741 | while i < 3 {
742 | print("Hello three times")
743 | i += 1
744 | }
745 |
746 |
747 | var i = 0
748 | while i < attendeeList.count {
749 | let person = attendeeList[i]
750 | print("\(person) is at position #\(i)")
751 | i += 1
752 | }
753 | ```
754 |
755 | ## Golden Path
756 |
757 | When coding with conditionals, 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.
758 |
759 | **Preferred:**
760 | ```swift
761 | func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
762 |
763 | guard let context = context else {
764 | throw FFTError.noContext
765 | }
766 | guard let inputData = inputData else {
767 | throw FFTError.noInputData
768 | }
769 |
770 | // use context and input to compute the frequencies
771 |
772 | return frequencies
773 | }
774 | ```
775 |
776 | **Not Preferred:**
777 | ```swift
778 | func computeFFT(context: Context?, inputData: InputData?) throws -> Frequencies {
779 |
780 | if let context = context {
781 | if let inputData = inputData {
782 | // use context and input to compute the frequencies
783 |
784 | return frequencies
785 | } else {
786 | throw FFTError.noInputData
787 | }
788 | } else {
789 | throw FFTError.noContext
790 | }
791 | }
792 | ```
793 |
794 | When multiple optionals are unwrapped either with `guard` or `if let`, minimize nesting by using the compound version when possible. Example:
795 |
796 | **Preferred:**
797 | ```swift
798 | guard let number1 = number1,
799 | let number2 = number2,
800 | let number3 = number3 else {
801 | fatalError("impossible")
802 | }
803 | // do something with numbers
804 | ```
805 |
806 | **Not Preferred:**
807 | ```swift
808 | if let number1 = number1 {
809 | if let number2 = number2 {
810 | if let number3 = number3 {
811 | // do something with numbers
812 | } else {
813 | fatalError("impossible")
814 | }
815 | } else {
816 | fatalError("impossible")
817 | }
818 | } else {
819 | fatalError("impossible")
820 | }
821 | ```
822 |
823 | ### Failing Guards
824 |
825 | Guard statements are required to exit in some way. Generally, this should be simple one line statement such as `return`, `throw`, `break`, `continue`, and `fatalError()`. Large code blocks should be avoided. If cleanup code is required for multiple exit points, consider using a `defer` block to avoid cleanup code duplication.
826 |
827 | ## Semicolons
828 |
829 | 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.
830 |
831 | Do not write multiple statements on a single line separated with semicolons.
832 |
833 | **Preferred:**
834 | ```swift
835 | let swift = "not a scripting language"
836 | ```
837 |
838 | **Not Preferred:**
839 | ```swift
840 | let swift = "not a scripting language";
841 | ```
842 |
843 | **NOTE**: Swift is very different from JavaScript, where omitting semicolons is [generally considered unsafe](http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript)
844 |
845 | ## Parentheses
846 |
847 | Parentheses around conditionals are not required and should be omitted.
848 |
849 | **Preferred:**
850 | ```swift
851 | if name == "Hello" {
852 | print("World")
853 | }
854 | ```
855 |
856 | **Not Preferred:**
857 | ```swift
858 | if (name == "Hello") {
859 | print("World")
860 | }
861 | ```
862 |
863 | ## References
864 |
865 | * [The Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/)
866 | * [The Swift Programming Language](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)
867 | * [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html)
868 | * [Swift Standard Library Reference](https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/index.html)
--------------------------------------------------------------------------------
/Swift/screens/indentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakingSense/code-style-guides/517b852480c0acfe6d6fb5f95f32fceddab1f0fe/Swift/screens/indentation.png
--------------------------------------------------------------------------------
/Swift/screens/xcode-jump-bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakingSense/code-style-guides/517b852480c0acfe6d6fb5f95f32fceddab1f0fe/Swift/screens/xcode-jump-bar.png
--------------------------------------------------------------------------------