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