├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution Guidelines
2 |
3 | Please ensure your pull request follows these guidelines.
4 |
5 | - **Make individual pull requests for every code example or topic you want to add.**
6 | - Only make a pull request for complete code examples, topics or cheat sheet items. If you have an idea or suggestion, use [Issues](https://github.com/reinder42/SwiftCheatsheet/issues).
7 | - Search previous suggestions before adding a new one – it may be a duplicate.
8 | - Be mindful of formatting. It's best to start with a bit of text like "Variables are ...", then a code example, then some more text explaining the example, and then some further deeper examples.
9 | - New topics, improvements of existing code examples etc. are welcome. Remember, it's a cheatsheet, not the Swift reference guide.
10 | - Please make jargon and Swift lingo like _nil-coalescing operator_ cursive by wrapping it in `_` underscores. Use indents or backticks for code.
11 | - Check your spelling and grammar. Test your code in Playgrounds or a Swift Sandbox. Make sure to use the most recent Swift version.
12 |
13 | Your contributions are always welcome! Thanks for making the world a better place :-)
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Reinder de Vries
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Swift 5 Cheatsheet
2 |
3 | A cheatsheet for Swift 5. Including examples of common Swift code and short explanations of what it does and how it works. Perfect for beginner iOS developers!
4 |
5 | ## How to Use
6 |
7 | The cheatsheet is in Markdown format. Simply read the cheatsheet online, or download the repository and open it. Use your favorite Markdown editor to export to PDF or HTML.
8 |
9 | Although we'd love for you to print it out and hang it on your desk, please think about the environment.
10 |
11 | ## Contributing
12 |
13 | Want to help create the most comprehensive (and concise!) Swift cheatsheet ever? There's a few ways you can help:
14 |
15 | - Suggest code examples, topics and cheat sheet items by [creating an Issue](https://github.com/reinder42/SwiftCheatsheet/issues)
16 | - Add your own code examples by creating a Pull Request
17 | - Share this cheatsheet with iOS developers you know to spread the word
18 |
19 | For more information, please check the [contribution guidelines](https://github.com/reinder42/SwiftCheatsheet/blob/master/CONTRIBUTING.md).
20 |
21 | Distributed under the MIT license. See [LICENSE](LICENSE) for more information.
22 |
23 | ## Table Of Contents
24 |
25 | - [Variables](#variables)
26 | - [Functions](#functions)
27 | - [Operators](#operators)
28 | - [Classes, Objects, Properties](#oop)
29 | - [Structs](#structs)
30 | - [Protocols](#protocols)
31 | - [Control Flow](#control-flow)
32 | + [Conditionals](#conditionals)
33 | + [Loops](#loops)
34 | + [Switch](#switch)
35 | - [Strings](#strings)
36 | - [Optionals](#optionals)
37 | - [Collections](#collections)
38 | + [Arrays](#arrays)
39 | + [Dictionaries](#dictionaries)
40 | + [Sets](#sets)
41 | - [Closures](#closures)
42 | - [Guard and Defer](#guard-defer)
43 | + [Guard](#guard)
44 | + [Defer](#defer)
45 | - [Generics](#generics)
46 | - [Tuples](#tuples)
47 | - [Enumerations](#enums)
48 | - [Error Handling](#error-handling)
49 | - [Commenting](#commenting)
50 | - [Resources](#resources)
51 |
52 | ## Variables
53 |
54 | Use `var` for variables that can change ("mutable") and `let` for constants that can't change ("non-mutable").
55 |
56 | _Integers_ are "whole" numbers, i.e. numbers without a fractional component.
57 |
58 | ```swift
59 | var meaningOfLife: Int = 42
60 | ```
61 |
62 | _Floats_ are decimal-point numbers, i.e. numbers with a fractional component.
63 |
64 | ```swift
65 | var phi: Float = 1.618
66 | ```
67 |
68 | _Doubles_ are floating point numbers with double precision, i.e. numbers with a fractional component. Doubles are preferred over floats.
69 |
70 | ```swift
71 | let pi: Double = 3.14159265359
72 | ```
73 |
74 | A _String_ is a sequence of characters, like text.
75 |
76 | ```swift
77 | var message: String = "Hello World!"
78 | ```
79 |
80 | A _boolean_ can be either `true` or `false`. You use booleans for logical operations.
81 |
82 | ```swift
83 | var isLoggedIn: Bool = false
84 | ```
85 |
86 | You can assign the result of an expression to a variable, like this:
87 |
88 | ```swift
89 | var result: Int = 1 + 2
90 | ```
91 |
92 | An _expression_ is programmer lingo for putting stuff like variables, operators, constants, functions, etc. together. Like `a + b` in this example:
93 |
94 | ```swift
95 | let a = 3
96 | let b = 4
97 | let c = a + b
98 | ```
99 |
100 | Swift can determine the _type_ (`Int`, `Double`, `String`, etc.) of a variable on its own. This is called _type inference_. In this example, the type of `name` is inferred to be `String`.
101 |
102 | ```swift
103 | var name = "Arthur Dent"
104 | ```
105 |
106 | Variables can be _optional_, which means it either contains a value or it's `nil`. Optionals make coding Swift safer and more productive. Here's an optional string:
107 |
108 | ```swift
109 | var optionalMessage: String?
110 | ```
111 |
112 | ## Functions
113 |
114 | _Functions_ are containers of Swift code. They have input and output. You often use functions to create abstractions in your code, and to make your code reusable.
115 |
116 | Here's an example of a function:
117 |
118 | ```swift
119 | func greetUser(name: String, bySaying greeting:String = "Hello") -> String
120 | {
121 | return "\(greeting), \(name)"
122 | }
123 | ```
124 |
125 | This function has two _parameters_ called `name` and `greeting`, both of type `String`. The second parameter `greeting` has an _argument label_ `bySaying`. The return type of the function is `String`, and its code is written between those squiggly brackets.
126 |
127 | You call the function like the following. The function is called, with two arguments, and the return value of the function is assigned to `message`.
128 |
129 | ```swift
130 | let message = greetUser(name: "Zaphod", bySaying: "Good Morning")
131 | ```
132 |
133 | Courses, books, documentation, etc. uses a special notation for function signatures. It'll use the function name and argument labels, like `greetUser(name:bySaying:)`, to describe the function.
134 |
135 | ## Operators
136 |
137 | The _assignment operator_ `=` assigns what's right of the operator to what's left of the operator. Don't confuse it with `==`!
138 |
139 | ```swift
140 | let age = 42
141 | ```
142 |
143 | Swift has a few basic math operators:
144 |
145 | - `a + b` for _addition_ (works for strings too)
146 | - `a - b` for _subtraction_
147 | - `a * b` for _multiplication_
148 | - `a / b` for _division_
149 | - `a % b` for _remainder_ (or use `isMultiple(of:)`)
150 | - `-a` for _minus_ (invert sign)
151 |
152 | Unlike other programming languages, Swift does not have `--` and `++` operators. Instead it has:
153 |
154 | - `a += b` for _addition_, such as `n += 1` for `n++` or `n = n + 1`
155 | - `a -= b` for _subtraction_, such as `n -= 1` for `n--` or `n = n - 1`
156 |
157 | You can also use `+=` for arrays:
158 |
159 | ```swift
160 | var rappers = ["Eminem", "Jay-Z", "Snoop Dogg"]
161 | rappers += ["Tupac"]
162 | ```
163 |
164 | Swift has 6 comparison operators:
165 |
166 | - `a == b` for _equality_, i.e. "a is equal to b"
167 | - `a != b` for _inequality_, i.e. "a is not equal to b"
168 | - `a > b` for _greater than_, i.e. "a is greater than b"
169 | - `a < b` for _less than_, i.e. "a is less than b"
170 | - `a >= b` for _greater than or equal_
171 | - `a <= b` for _less than or equal_
172 |
173 | Swift also has the identity operators `===` and `!==`. You can use them to test if two variables reference the exact _same object_. Contrast this with `==` and `!=`, which merely test if two objects are equal to each other.
174 |
175 | You can also compare strings, which is helpful for sorting. Like this:
176 |
177 | ```swift
178 | "abc" > "xyz" // false
179 | "Starbucks" > "Costa" // true
180 | "Alice" < "Bob" // true
181 | ```
182 |
183 | Swift has 3 logical operators:
184 |
185 | - `a && b` for _Logical AND_, returns `true` if `a` and `b` are `true`, or `false` otherwise
186 | - `a || b` for _Logical OR_, returns `true` if either `a` or `b` is `true`, or both are `true`, or `false` otherwise
187 | - `!a` for _Logical NOT_, returns `true` if `a` is `false`, and `false` if `a` is `true` (i.e., the opposite of `a`)
188 |
189 | Swift has a few range operators. You can use them to define ranges of numbers and strings.
190 |
191 | - `a...b`, the _closed range operator_, defines a range from `a` to `b` including `b`
192 | - `a.. Classes, Objects, Properties
201 |
202 | Classes are basic building blocks for apps. They can contain functions, sometimes called _methods_, and variables, called _properties_.
203 |
204 | ```swift
205 | class Office: Building, Constructable
206 | {
207 | var address: String = "1 Infinite Loop"
208 | var phone: String?
209 |
210 | @IBOutlet weak var submitButton:UIButton?
211 |
212 | lazy var articles:String = {
213 | return Database.getArticles()
214 | }()
215 |
216 | override init()
217 | {
218 | address = "1 Probability Drive"
219 | }
220 |
221 | func startWorking(_ time:String, withWorkers workers:Int)
222 | {
223 | print("Starting working at time \(time) with workers \(workers)")
224 | }
225 | }
226 | ```
227 |
228 | The class definition starts with `class`, then the class name `Office`, then the `Building` class it _inherits_ from, and then the `Constructable` _protocol_ it conforms to. Inheritance, protocols, all that stuff, is part of _Object-Oriented Programming_.
229 |
230 | Properties are variables that belong to a class instance. This class has 4 of them: `address`, `phone`, the outlet `submitButton` and the lazy computed property `articles`. Properties can have a number of attributes, like `weak` and `@IBOutlet`.
231 |
232 | The function `init()` is _overridden_ from the superclass `Building`. The class `Office` is a _subclass_ of `Building`, so it inherits all functions and properties that `Building` has.
233 |
234 | You can create an _instance_ of a class, and change its properties, like this:
235 |
236 | ```swift
237 | let buildingA = Office()
238 | buildingA.address = "Sector ZZ9 Plural Z Alpha"
239 | ```
240 |
241 | Extensions let you add new functions to existing types. This is useful in scenarios where you can't change the code of a class. Like this:
242 |
243 | ```swift
244 | extension Building
245 | {
246 | func evacuate() {
247 | print("Please leave the building in an orderly fashion.")
248 | }
249 | }
250 | ```
251 |
252 | ## Structs
253 |
254 | Structs or _structures_ in Swift allow you to encapsulate related properties and functionality in your code, that you can reuse. Structs are value types.
255 |
256 | We declare them like this:
257 |
258 | ```swift
259 | struct Jedi {
260 | var name: String
261 | var midichlorians: Int
262 | }
263 | ```
264 |
265 | You can create an instance of the `Jedi` struct like this:
266 |
267 | ```swift
268 | var obi_wan = Jedi(name: "Obi-Wan Kenobi", midichlorians: 13400)
269 | ```
270 |
271 | Here's how you can read a property from `obi_wan`:
272 |
273 | ```swift
274 | print(obi_wan.midichlorians)
275 | // Output: 13400
276 | ```
277 |
278 | We can also include functions inside our structs, like this:
279 |
280 | ```swift
281 | struct Jedi {
282 | var name: String
283 | var midichlorians: Int
284 |
285 | func mindTrick() {
286 | print("These aren't the Droids you're looking for...")
287 | }
288 | }
289 |
290 | // Instance of a struct
291 | var obi_wan = Jedi(name: "Obi-Wan Kenobi", midichlorians: 13400)
292 |
293 | // Reading a property
294 | print(obi_wan.midichlorians)
295 |
296 | // Calling mindTrick() function
297 | obi_wan.mindTrick()
298 | ```
299 |
300 | ## Protocols
301 |
302 | Protocols define a "contract"; a set of functions and properties that a type, like a class, must implement if it wants to _conform_ to the protocol.
303 |
304 | Protocols are declared like this:
305 |
306 | ```swift
307 | protocol Healer {
308 | func heal()
309 | }
310 | ```
311 |
312 | In this example Imperial troops are fine on their own, but can conform to the `Healer` protocol and support their fellow troopers in combat:
313 |
314 | ```swift
315 | protocol Healer {
316 | func heal()
317 | }
318 |
319 | struct TiePilot {
320 | var starfigherModel: String = "TIE/IN Interceptor"
321 | var rank: String = "Lieutenant"
322 | }
323 |
324 | struct StormTrooper: Healer {
325 | var name: String = "TK-9091"
326 | var unit: String = "501st Legion"
327 |
328 | func heal() {
329 | print("Deploying Advanced Medical Probe!")
330 | }
331 | }
332 | ```
333 |
334 | You can also use protocols as types. Like this:
335 |
336 | ```swift
337 | struct Squadron
338 | {
339 | var leader: EliteStormTrooper
340 | var troopers: [StormTrooper]
341 | var healer: Healer
342 |
343 | func init(...) { ... }
344 | }
345 |
346 | var squad5 = Squadron(...)
347 | squad5.healer = StormTrooper(...)
348 | ```
349 |
350 | In the above code, you can assign an object of type `StormTrooper` to the `healer` property of type `Healer`, because the `StormTrooper` type conforms to the `Healer` protocol. You can assign anything to it, as long as it conforms to the right protocol.
351 |
352 | ## Control Flow
353 |
354 | ### Conditionals
355 |
356 | This is an `if`-statement, or _conditional_. You use them to make decisions based on logic.
357 |
358 | ```swift
359 | if isActive
360 | {
361 | print("This user is ACTIVE!")
362 | } else {
363 | print("Inactive user...")
364 | }
365 | ```
366 |
367 | You can combine multiple conditionals with the `if-elseif-else` syntax, like this:
368 |
369 | ```swift
370 | var user:String = "Bob"
371 |
372 | if user == "Alice" && isActive
373 | {
374 | print("Alice is active!")
375 | }
376 | else if user == "Bob" && !isActive
377 | {
378 | print("Bob is lazy!")
379 | }
380 | else
381 | {
382 | print("When none of the above are true...")
383 | }
384 | ```
385 |
386 | The `&&` is the _Logical AND_ operator. You use it to create logical expressions that can be evaluated to `true` or `false`. Like this:
387 |
388 | ```swift
389 | if user == "Deep Thought" || meaningOfLife == 42
390 | {
391 | print("The user is Deep Thought, or the meaning of life is 42...")
392 | }
393 | ```
394 |
395 | Operators, like `&&`, have an order of _precedence_. This determines which operator has priority over another; which operator is evaluated before the other. Check this out:
396 |
397 | ```swift
398 | let a = 2 + 3 * 4
399 | // Output: 14
400 | ```
401 |
402 | The value of `a` is 14 and not 20, because multiplication precedes addition. A quick overview: `! * / + - && ||`.
403 |
404 | You can change the order of operations with parentheses. Like this:
405 |
406 | ```swift
407 | let a = (2 + 3) * 4
408 | // Output: 20
409 | ```
410 |
411 | This groups the addition, which is now evaluated before the multiplication. Precedence rules are especially important when working with the logical `&&` (AND) and `||` (OR) operators. `&&` goes before `||`. Check this out:
412 |
413 | ```swift
414 | let isPresident = true
415 | let threatLevel = 1
416 | let officerRank = 1
417 |
418 | if threatLevel > 5 && officerRank >= 3 || isPresident {
419 | print("(1) FIRE ROCKETS!!!")
420 | }
421 |
422 | if threatLevel > 5 && (officerRank >= 3 || isPresident) {
423 | print("(2) FIRE ROCKETS!!!")
424 | }
425 | // Output: (1) FIRE ROCKETS!!!
426 | ```
427 |
428 | Notice how the result of the above conditionals changes based on the parentheses, while their operators and operands stay the same.
429 |
430 | - In the first conditional, the rockets are fired because `isPresident` is `true` and the entire conditional evaluates to `(false && false -> false) || true -> false || true -> true`.
431 | - In the second conditional, the rockets aren't fired even though `isPresident` is `true`. The entire conditional evaluates to `false && (false || true -> true) -> false && true -> false`.
432 |
433 | Swift has a special operator, called the _ternary conditional operator_. It's coded as `a ? b : c`. If `a` is `true`, the expression returns `b`, and if `a` is `false`, the expression returns `c`. It's the equivalent of this:
434 |
435 | ```swift
436 | if a {
437 | b
438 | } else {
439 | c
440 | }
441 | ```
442 |
443 | ### Loops
444 |
445 | Loops repeat stuff. It's that easy. Like this:
446 |
447 | ```swift
448 | for i in 1...5 {
449 | print(i)
450 | }
451 | // Output: 1 2 3 4 5
452 | ```
453 |
454 | This prints `1` to `5`, including `5`! You can also use the _half-open range operator_ `a.. 0 {
487 | steps -= 9
488 | print(steps)
489 | }
490 | // Output: 33 24 15 6 -3
491 | ```
492 |
493 | A `while` loop will evaluate its condition _at the top_ of the loop, so before the next iteration runs. The `repeat-while` evaluates its condition _at the end_ of the loop. It'll always run the first iteration, before evaluating the loop condition.
494 |
495 | ### Switch
496 |
497 | A `switch` statement takes a value and compares it against one of several _cases_. It's similar to the `if-else if-else` conditional, and it's an elegant way of dealing with multiple states.
498 |
499 | An example:
500 |
501 | ```swift
502 | enum WeatherType {
503 | case rain, clear, sunny, overcast, tsunami, earthquake, snow;
504 | }
505 |
506 | let weather = WeatherType.sunny
507 |
508 | switch weather
509 | {
510 | case .rain:
511 | print("Bring a raincoat!")
512 | case .clear, .sunny:
513 | print("Don't forget your sunglasses.")
514 | case .overcast:
515 | print("It's really depressing.")
516 | case .tsunami, .earthquake:
517 | print("OH NO! BIG WAVE!")
518 | default:
519 | print("Expect the best, prepare for the worst.")
520 | }
521 | ```
522 |
523 | In Swift, `switch` statements don't have an implicit _fall-through_, but you can use `fallthrough` explicitly. Every case needs to have at least one line of code in it. You don't have to use a `break` explicitly to end a case.
524 |
525 | The `switch` cases need to be _exhaustive_. For example, when working with an `enum`, you'll need to incorporate every value in the enumeration. You can also provide a `default` case, which is similar to `else` in a conditional.
526 |
527 | You can also use Swift _ranges_ to match interval for numbers, use tuples to match partial values, and use Swift's `where` keyword to check for additional conditions.
528 |
529 | ## Strings
530 |
531 | Strings are pretty cool. Here's an example:
532 |
533 | ```swift
534 | var jobTitle: String = "iOS App Developer"
535 | ```
536 |
537 | Inside a string, you can use _string interpolation_ to string together multiple strings. Like this:
538 |
539 | ```swift
540 | var hello = "Hello, \(jobTitle)"
541 | // Output: Hello, iOS App Developer
542 | ```
543 |
544 | You can also use the `+` addition operator to concatenate multiple strings:
545 |
546 | ```swift
547 | let a = "Never gonna"
548 | let b = "give you up"
549 | let rr = a + " " + b
550 | ```
551 |
552 | You can also turn an `Int` into a `String`:
553 |
554 | ```swift
555 | let number = 42
556 | let numberAsString = "\(number)"
557 | ```
558 |
559 | And vice-versa:
560 |
561 | ```swift
562 | let number = "42"
563 | let numberAsInt = Int(number)
564 | ```
565 |
566 | You can loop over the characters of a string like this:
567 |
568 | ```swift
569 | let text = "Forty-two!"
570 |
571 | for char in text {
572 | print(char)
573 | }
574 | ```
575 |
576 | You can get individual characters and character ranges by using _indices_, like this:
577 |
578 | ```swift
579 | let text = "Forty-two!"
580 | text[text.startIndex] // F
581 | text[text.index(before: text.endIndex)] // !
582 | text[text.index(text.startIndex, offsetBy: 3)] // t
583 | text[.. Optionals
595 |
596 | _Optionals_ can either be `nil` or contain a value. You **must** always _unwrap_ an optional before you can use it.
597 |
598 | This is Bill. Bill is an optional.
599 |
600 | ```swift
601 | var bill: String? = nil
602 | ```
603 |
604 | You can unwrap `bill` in a number of ways. First, this is _optional binding_.
605 |
606 | ```swift
607 | if let definiteBill = bill {
608 | print(definiteBill)
609 | }
610 | ```
611 |
612 | In this example, you bind the non-optional value from `bill` to `definiteBill` _but only when `bill` is not `nil`_. It's like asking: "Is it not `nil`?" OK, if not, then assign it to this constant and execute that stuff between the squiggly brackets.
613 |
614 | You can also use _force-unwrapping_ to unwrap an optional. Like this:
615 |
616 | ```swift
617 | var droid: String? = "R2D2"
618 |
619 | if droid != nil {
620 | print("This is not the droid you're looking for: \(droid!)")
621 | }
622 | ```
623 |
624 | See how that `droid` is force-unwrapped with the exclamation mark `!`? You should keep in mind that if `droid` is `nil` when you force-unwrap it, your app will crash.
625 |
626 | You can also use _optional chaining_ to work your way through a number of optionals. This saves you from coding too much optional binding blocks. Like this:
627 |
628 | ```swift
629 | view?.button?.title = "BOOYAH!"
630 | ```
631 |
632 | In this code, `view`, `button` and `title` are all optionals. When `view` is `nil`, the code "stops" before `button`, so the `button` property is never accessed.
633 |
634 | One last thing... the _nil-coalescing operator_. You can use it to provide a default value when an expression results in `nil`. Like this:
635 |
636 | ```swift
637 | var meaningOfLife = deepThought.think() ?? 42
638 | ```
639 |
640 | See that `??`. When `deepThought.think()` returns `nil`, the variable `meaningOfLife` is `42`. When that function returns a value, it's assigned to `meaningOfLife`.
641 |
642 | ## Collections
643 |
644 | ### Arrays
645 |
646 | Arrays are a collection type. Think of it as a variable that can hold multiple values, like a closet that can contain multiple drawers. Arrays always have _numerical_ index values. Arrays always contain elements of the same type.
647 |
648 | ```swift
649 | var hitchhikers = ["Ford", "Arthur", "Zaphod", "Trillian"]
650 | ```
651 |
652 | You can add items to the array:
653 |
654 | ```swift
655 | hitchhikers += ["Marvin"]
656 | ```
657 |
658 | You can get items from the array with _subscript syntax_:
659 |
660 | ```swift
661 | let arthur = hitchhikers[1]
662 | ```
663 |
664 | Remember that arrays are _zero-index_, so the index number of the first element is `0` (and not `1`).
665 |
666 | You can iterate arrays, like this:
667 |
668 | ```swift
669 | for name in hitchhikers {
670 | print(name)
671 | }
672 | ```
673 |
674 | A helpful function on arrays is `enumerated()`. It lets you iterate index-value pairs, like this:
675 |
676 | ```swift
677 | for (index, name) in hitchhikers.enumerated() {
678 | print("\(index) = \(name)")
679 | }
680 | ```
681 |
682 | ### Dictionaries
683 |
684 | Dictionaries are also collection types. The items in a dictionary consists of key-value pairs. Unlike arrays, you can set your own key type. Like this:
685 |
686 | ```swift
687 | var score = [
688 | "Fry": 10,
689 | "Leela": 29,
690 | "Bender": 1,
691 | "Zoidberg": 0
692 | ]
693 | ```
694 |
695 | What's the type of this dictionary? It's `[String: Int]`. Just like with arrays, you can use _subscript syntax_ to get the value for a key:
696 |
697 | ```swift
698 | print(score["Leela"])
699 | // Output: 29
700 | ```
701 |
702 | You can add a key-value pair to a dictionary like this:
703 |
704 | ```swift
705 | score["Amy"] = 9001
706 | ```
707 |
708 | Change it like this:
709 |
710 | ```swift
711 | score["Bender"] = -1
712 | ```
713 |
714 | And remove it like this:
715 |
716 | ```swift
717 | score.removeValue(forKey: "Zoidberg")
718 | ```
719 |
720 | You can also iterate a dictionary, like this:
721 |
722 | ```swift
723 | for (name, points) in score
724 | {
725 | print("\(name) has \(points) points");
726 | }
727 | ```
728 |
729 | ### Sets
730 |
731 | _Sets_ in Swift are similar to arrays and dictionaries. Just like arrays and dictionaries, the `Set` type is used to store multiple items of the same type in one collection.
732 |
733 | Here's an example:
734 |
735 | ```swift
736 | var fruit:Set = ["apple", "banana", "strawberry", "jackfruit"]
737 | ```
738 |
739 | You can add and remove items like this:
740 |
741 | ```swift
742 | fruit.insert("pineapple")
743 | fruit.remove("banana")
744 | ```
745 |
746 | Sets are different from arrays and dictionaries, in these ways:
747 |
748 | - Sets don't have an order – they're literally unsorted
749 | - Every item in a set needs to be unique
750 | - Sets don't have indices or keys
751 | - Instead, a set's values need to be _hashable_
752 | - Because set items are hashable, you can search sets in _O(1)_ time
753 |
754 | Here's how you can quickly search a set:
755 |
756 | ```swift
757 | let movies:Set = ["Rocky", "The Matrix", "Lord of the Rings"]
758 |
759 | if movies.contains("Rocky") {
760 | print("Rocky is one of your favorite movies!")
761 | }
762 | ```
763 |
764 | Sets are particularly useful for membership operations, to find out if sets have items in common for example. We can make a union of sets, subtract sets, intersect them, and find their differences.
765 |
766 | Consider the following Italian coffees and their ingredients:
767 |
768 | ```swift
769 | let cappuccino:Set = ["espresso", "milk", "milk foam"]
770 | let americano:Set = ["espresso", "water"]
771 | let machiato:Set = ["espresso", "milk foam"]
772 | let latte:Set = ["espresso", "milk"]
773 | ```
774 |
775 | Can we find the **union** (add items) of two coffees?
776 |
777 | ```swift
778 | machiato.union(latte)
779 | // ["espresso", "milk foam", "milk"]
780 | ```
781 |
782 | Can we **subtract** one coffee from another?
783 |
784 | ```swift
785 | cappuccino.subtracting(americano)
786 | // ["milk foam", "milk"]
787 | ```
788 |
789 | Can we find the **intersection** (shared items) of two coffees?
790 |
791 | ```swift
792 | latte.intersection(cappuccino)
793 | // ["espresso", "milk"]
794 | ```
795 |
796 | Can we find the **difference** between two coffees?
797 |
798 | ```swift
799 | latte.symmetricDifference(americano)
800 | // ["milk", "water"]
801 | ```
802 |
803 | ## Closures
804 |
805 | With _closures_ you can pass around blocks of code, like functions, as if they are variables. You use them, for example, by passing a callback to a lengthy task. When the task ends, the callback – a closure – is executed.
806 |
807 | You define a closure like this:
808 |
809 | ```swift
810 | let authenticate = { (name: String, userLevel: Int) -> Bool in
811 | return (name == "Bob" || name == "Alice") && userLevel > 3
812 | }
813 | ```
814 |
815 | You call the closure like this:
816 |
817 | ```swift
818 | authenticate("Bob", 7)
819 | ```
820 |
821 | Closures have a type, that reflect the closure's parameters and its return type. The type of the closure for `authenticate` is `(String, Int) -> Bool`.
822 |
823 | If we had a user interface for authenticating a user, then we could pass the closure as a callback like this:
824 |
825 | ```swift
826 | let loginVC = MyLoginViewController(withAuthCallback: authenticate)
827 | ```
828 |
829 | You always write a closure inside squiggly brackets `{ }`. Within the closure, you can declare zero, one or more parameters (with types), and optionally, a return type, followed by `in`.
830 |
831 | Closure syntax is flexible, and has a few shorthands, which means you can leave out parts of the closure's declaration to make the code more concise.
832 |
833 | For example, the closure in this code:
834 |
835 | ```swift
836 | let names = ["Zaphod", "Trillian", "Ford", "Arthur", "Marvin"]
837 | let sortedNames = names.sorted(by: <)
838 | ```
839 |
840 | ... is the same as this code:
841 |
842 | ```swift
843 | names.sorted(by: { (s1: String, s2: String) -> Bool in
844 | return s1 < s2
845 | })
846 | ```
847 |
848 | ... and that's the same as this, too:
849 |
850 | ```swift
851 | names.sorted(by: { s1, s2 in s1 < s2 } )
852 | ```
853 |
854 | ... and even this, too:
855 |
856 | ```swift
857 | names.sorted { $0 < $1 }
858 | ```
859 |
860 | Another use case for closures is multi-threading with Grand Central Dispatch. Like this:
861 |
862 | ```swift
863 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(60)) {
864 | // Dodge this!
865 | }
866 | ```
867 |
868 | In the above example, the last argument of `asyncAfter(deadline:execute:)` is a closure. It uses the _trailing closure_ syntax. When a closure is the last argument of a function call, you can write it after the function call parentheses and omit the argument label.
869 |
870 | ## Guard and Defer
871 |
872 | ### Guard
873 |
874 | The `guard` statement helps you to return functions early. It's a conditional, and when it isn't met you need to exit the function with `return`.
875 |
876 | Like this:
877 |
878 | ```swift
879 | func loadTweets(forUserID userID: Int)
880 | {
881 | guard userID > 0 else {
882 | return
883 | }
884 |
885 | // Load the tweets...
886 | }
887 | ```
888 |
889 | You can read that as: _"Guard that the User ID is greater than zero, or else, exit this function"_. Guard is especially powerful when you have multiple conditions that should return the function.
890 |
891 | Guard blocks always need to exit its enclosing scope, i.e. transfer control outside of the scope, by using `return`, `throw`, `break` or `continue`.
892 |
893 | You can also combine `guard` and `if let` (optional binding) into `guard let`. This checks if the given expression is not `nil`, and assigns it to a constant. When the expression is `nil`, the `else` clause of `guard` is executed.
894 |
895 | ```swift
896 | guard let user = object?.user else {
897 | return
898 | }
899 | ```
900 |
901 | You can now use the `user` constant in the rest of the scope, below the `guard let` block.
902 |
903 | ### Defer
904 |
905 | With `defer` you can define a code block that's executed when your function returns. The `defer` statement is similar to `guard`, because it also helps with the flow of your code.
906 |
907 | Like this:
908 |
909 | ```swift
910 | func saveFile(withData data: Data) {
911 |
912 | let filePointer = openFile("../example.txt")
913 |
914 | defer {
915 | closeFile(filePointer)
916 | }
917 |
918 | if filePointer.size > 0 {
919 | return
920 | }
921 |
922 | if data.size > 512 {
923 | return
924 | }
925 |
926 | writeFile(filePointer, withData: data)
927 | }
928 | ```
929 |
930 | In the example code you're opening a file and writing some data to it. As a rule, you need to close the file pointer before exiting the function.
931 |
932 | The file isn't written to when two conditions aren't met. You have to close the file at those points. Without the `defer` statement, you would have written `closeFile(_:)` twice.
933 |
934 | Thanks to `defer`, the file is always closed when the function returns.
935 |
936 | ## Generics
937 |
938 | In Swift your variables are _strong typed_. When you set the type of animals your farm can contain to `Duck`, you can't change that later on. With _generics_ however, you can!
939 |
940 | Like this:
941 |
942 | ```swift
943 | func insertAnimal(_ animal: T, inFarm farm: Farm)
944 | {
945 | // Insert `animal` in `farm`
946 | }
947 | ```
948 |
949 | This is a _generic function_. It uses a _placeholder type_ called `T` instead of an actual type name, like `String`.
950 |
951 | If you want to insert ducks, cows, birds and chickens in your farm, you can now do that with one function instead of 4.
952 |
953 | ## Tuples
954 |
955 | With _tuples_ you get two (or more) variables for one. They help you structure your code better. Like this:
956 |
957 | ```swift
958 | let coffee = ("Cappuccino", 3.99)
959 | ```
960 |
961 | You can now get the price of the coffee like this:
962 |
963 | ```swift
964 | let (name, price) = coffee
965 | print(price)
966 | // Output: 3.99
967 | ```
968 |
969 | When you need just the name, you can do this:
970 |
971 | ```swift
972 | let (name, _) = coffee
973 | print(name)
974 | // Output: Cappuccino
975 | ```
976 |
977 | You can also name the elements of a tuple, like this:
978 |
979 | ```swift
980 | let flight = (code: "XJ601", heading: "North", passengers: 216)
981 | print(flight.heading)
982 | // Output: North
983 | ```
984 |
985 | ## Enumerations
986 |
987 | With enumerations, also known as enums, you can organize groups of values that are related. Here's an example:
988 |
989 | ```swift
990 | enum Compass {
991 | case north
992 | case east
993 | case south
994 | case west
995 | }
996 | ```
997 |
998 | Here's how you use them:
999 |
1000 | ```swift
1001 | let direction: Compass = .south
1002 | ```
1003 |
1004 | Enums and the `switch` statement are a powerful couple. Here's an example:
1005 |
1006 | ```swift
1007 | enum Emotion {
1008 | case happy, sad, angry, scared, surprised
1009 | }
1010 |
1011 | switch robot.mood {
1012 | case .angry:
1013 | robot.destroyAllHumans()
1014 | case .sad:
1015 | robot.cry()
1016 | case .happy:
1017 | robot.play("happy.mp3")
1018 | case default:
1019 | print("Error: emotion not supported.")
1020 | }
1021 | ```
1022 |
1023 | You can also assign raw values to enums, by using existing Swift types like `String`. Here's an example:
1024 |
1025 | ```swift
1026 | enum Flavor:String {
1027 | case vanilla = "vanilla"
1028 | case strawberry = "strawberry"
1029 | case chocolate = "chocolate"
1030 | }
1031 | ```
1032 |
1033 | With this approach, you can get the string value for an enum like this:
1034 |
1035 | ```swift
1036 | let icecream = Flavor.vanilla
1037 | print(icecream.rawValue)
1038 | // Output: vanilla
1039 | ```
1040 |
1041 | You can now also use a string to create an enum, like this:
1042 |
1043 | ```swift
1044 | let icecream = Flavor(rawValue: "vanilla")
1045 | print(icecream)
1046 | // Output: Optional(Flavor.vanilla)
1047 | ```
1048 |
1049 | You can also associate values with individual cases of an enumeration, like this:
1050 |
1051 | ```swift
1052 | enum Item {
1053 | case weapon(Int, Int)
1054 | case food(Int)
1055 | case armor(Int, Int, Double)
1056 | }
1057 | ```
1058 |
1059 | You can now use the enumeration's associated values, like this:
1060 |
1061 | ```swift
1062 | func use(item: Item)
1063 | {
1064 | switch item {
1065 | case .weapon(let hitPoints, _):
1066 | player.attack(hitPoints)
1067 | case .food(let health):
1068 | player.health += health
1069 | case .armor(let damageThreshold, let weight, let condition):
1070 | player.damageThreshold = Double(damageThreshold) * condition
1071 | }
1072 | }
1073 | ```
1074 |
1075 | In the above code, we're using `hitPoints` to "attack" in case `item` is the enum type `weapon(Int, Int)`. This way you can associate additional values with an enum case.
1076 |
1077 | ## Error Handling
1078 |
1079 | Errors in Swift can be thrown, and should be caught. You can define an error type like this:
1080 |
1081 | ```swift
1082 | enum CreditCardError: Error {
1083 | case insufficientFunds
1084 | case issuerDeclined
1085 | case invalidCVC
1086 | }
1087 | ```
1088 |
1089 | When you code a function that can throw errors, you have to mark its function definition with `throws`. Like this:
1090 |
1091 | ```swift
1092 | func processPayment(creditcard: String) throws {
1093 | ...
1094 | ```
1095 |
1096 | Inside the function, you can then throw an error like this:
1097 |
1098 | ```swift
1099 | throw CreditCardError.insufficientFunds
1100 | ```
1101 |
1102 | When you _use_ a function that can throw errors, you have to wrap it in a `do-try-catch` block. Like this:
1103 |
1104 | ```swift
1105 | do {
1106 | try processPayment(creditcard: "1234.1234")
1107 | }
1108 | catch {
1109 | print(error)
1110 | }
1111 | ```
1112 |
1113 | In the example above, the `processPayment(creditcard:)` function is marked with the `try` keyword. When an error occurs, the `catch` block is executed.
1114 |
1115 | ## Commenting
1116 |
1117 | There are 3 types of comments:
1118 |
1119 | **1. Documentary**: Describes the history and development of the file. Their core purpose is to improve code maintainability. Most notable examples are:
1120 |
1121 | - Filename
1122 | - Project name
1123 | - Creation and modification dates
1124 | - Author
1125 | - Copyright
1126 | - Version
1127 | - History of changes
1128 | - Dependencies
1129 |
1130 | Documentary comments are wordy and error-prone if typed manually. Capture only those details, which are not available to version controls tools like git.
1131 |
1132 | We are dealing with documentary comments every day, often without realizing it:
1133 |
1134 | ```swift
1135 | //
1136 | // AppDelegate.swift
1137 | //
1138 | // Created by John Doe on 28/7/20.
1139 | // Copyright © 2020 Acme Inc. All rights reserved.
1140 | //
1141 | ```
1142 |
1143 | **2. Functional**: Adds information and special directives to the development process. Most notable examples in Swift are:
1144 |
1145 | - Diagnostic directives: `#warning`, `#error`
1146 | - Annotations: `TODO`, `MARK`, `FIXME`, and 3rd-party-specific like `swiftlint:disable`
1147 | - Notes about who fixed what bug when, e.g. "Bugfix: This is how I fixed it. -VABU"
1148 | - Performance improvement notes
1149 |
1150 | **3. Explanatory**: Summarizes code or explains the programmer's intent. Explanatory comments must answer the question _why_ instead of _what_.
1151 |
1152 | Explanatory comments make the most sense in these scenarios:
1153 |
1154 | - Code does not fit project conventions
1155 | - Algorithm description: name, complexity, documentation
1156 | - Complex regular expressions
1157 | - Workarounds and hacks
1158 |
1159 | ### Comment Syntax
1160 |
1161 | Swift comments can be written in two formats:
1162 |
1163 | Each line is preceded by a double slash `//`
1164 |
1165 | ```swift
1166 | // <#Description#>
1167 | //
1168 | // - Parameter value: <#value description#>
1169 | // - Returns: <#return value description#>
1170 | func isOdd(_ value: Int) -> Bool {
1171 | return abs(value) % 2 == 1
1172 | }
1173 | ```
1174 |
1175 | Javadoc-style block comments `/* … */`
1176 |
1177 | ```swift
1178 | /* <#Description#>
1179 |
1180 | - Parameter value: <#value description#>
1181 | - Returns: <#return value description#>
1182 | */
1183 | func isOdd(_ value: Int) -> Bool {
1184 | return abs(value) % 2 == 1
1185 | }
1186 | ```
1187 |
1188 | ## Resources
1189 |
1190 | No cheatsheet is complete without a list of resources with more information. Wanna see how deep the rabbit hole really goes?
1191 |
1192 | - [Swift Language Guide](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html)
1193 | - [Swift Evolution](https://apple.github.io/swift-evolution/)
1194 | - [Swift Standard Library](https://developer.apple.com/documentation/swift)
1195 | - [Apple Developer Documentation](https://developer.apple.com/documentation/)
1196 | - [https://github.com/vsouza/awesome-ios](https://github.com/vsouza/awesome-ios)
1197 | - [https://github.com/matteocrippa/awesome-swift](https://github.com/matteocrippa/awesome-swift)
1198 | - [http://online.swiftplayground.run/](http://online.swiftplayground.run/)
1199 |
1200 |
--------------------------------------------------------------------------------