{"id":13538289,"url":"https://github.com/Luur/SwiftEchoes-Tips","last_synced_at":"2025-04-02T05:31:11.936Z","repository":{"id":41125435,"uuid":"123714762","full_name":"Luur/SwiftEchoes-Tips","owner":"Luur","description":"Swift tips and tricks","archived":false,"fork":false,"pushed_at":"2021-08-06T15:05:26.000Z","size":5827,"stargazers_count":974,"open_issues_count":2,"forks_count":72,"subscribers_count":62,"default_branch":"master","last_synced_at":"2024-11-03T03:31:14.124Z","etag":null,"topics":["iosdev","swift","tips-and-tricks"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Luur.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-03T17:25:02.000Z","updated_at":"2024-10-12T12:25:39.000Z","dependencies_parsed_at":"2022-07-12T18:17:47.698Z","dependency_job_id":null,"html_url":"https://github.com/Luur/SwiftEchoes-Tips","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Luur%2FSwiftEchoes-Tips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Luur%2FSwiftEchoes-Tips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Luur%2FSwiftEchoes-Tips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Luur%2FSwiftEchoes-Tips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Luur","download_url":"https://codeload.github.com/Luur/SwiftEchoes-Tips/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246763802,"owners_count":20829795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["iosdev","swift","tips-and-tricks"],"created_at":"2024-08-01T09:01:09.323Z","updated_at":"2025-04-02T05:31:11.355Z","avatar_url":"https://github.com/Luur.png","language":"Swift","funding_links":[],"categories":["Swift-Tips"],"sub_categories":["Swift之struct二进制大小分析"],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"Logo.png\" width=\"850\" max-width=\"100%\" alt=\"Swift Tips\" /\u003e\n\u003c/p\u003e\n\n# 🔥 SwiftEchoes - Tips\n\nHere's list of tips and tricks with all additional sources (playgrounds, images) that I would like to share. Also you can find them on [Twitter @szubyak](https://twitter.com/szubyak), where you can ask questions and respond with feedback. I will really glad to have you there! 😀\n\n## 📃 Table of contents\n\n[#63 How to make `UIStoryboard` usage safer?](https://github.com/Luur/SwiftTips#63-how-to-make-uistoryboard-usage-safer)\u003cbr /\u003e\n[#62 \"Massive\" Storyboard](https://github.com/Luur/SwiftTips#62-massive-storyboard)\u003cbr /\u003e\n[#61 `XCTUnwrap` assertion function](https://github.com/Luur/SwiftTips#61-xctunwrap-assertion-function)\u003cbr /\u003e\n[#60 `UITableViewCell` identifier](https://github.com/Luur/SwiftTips#60-uitableviewcell-identifier)\u003cbr /\u003e\n[#59 `AlertPresentable` protocol](https://github.com/Luur/SwiftTips#59-alertpresentable-protocol)\u003cbr /\u003e\n[#58 CollectionView extension for adaptive grid layout](https://github.com/Luur/SwiftTips#58-collectionview-extension-for-adaptive-grid-layout)\u003cbr /\u003e\n[#57 Render HTML within a `UILabel`](https://github.com/Luur/SwiftTips#57-render-html-within-a-uilabel)\u003cbr /\u003e\n[#56 Custom `Error` by adopting `LocalizedError` protocol](https://github.com/Luur/SwiftTips#56-custom-error-by-adopting-localizederror-protocol)\u003cbr /\u003e\n[#55 'Result' type without value to provide](https://github.com/Luur/SwiftTips#55-result-type-without-value-to-provide)\u003cbr /\u003e\n[#54 Given, When, Then](https://github.com/Luur/SwiftTips#54-given-when-then)\u003cbr /\u003e\n[#53 `sut` and test lifecycle](https://github.com/Luur/SwiftTips#53-sut-and-test-lifecycle)\u003cbr /\u003e\n[#52 Point on circle perimeter](https://github.com/Luur/SwiftTips#52-point-on-circle-perimeter)\u003cbr /\u003e\n[#51 `zip()` function](https://github.com/Luur/SwiftTips#51-zip-function)\u003cbr /\u003e\n[#50 StackView custom spacing](https://github.com/Luur/SwiftTips#50-stackview-custom-spacing)\u003cbr /\u003e\n[#49 Named UIColor](https://github.com/Luur/SwiftTips#49-named-uicolor)\u003cbr /\u003e\n[#48 `Result` error handling](https://github.com/Luur/SwiftTips#48-result-error-handling)\u003cbr /\u003e\n[#47 Generics: Type parameters](https://github.com/Luur/SwiftTips#47-generics-type-parameters)\u003cbr /\u003e\n[#46 Generics: Basics](https://github.com/Luur/SwiftTips#46-generics-basics)\u003cbr /\u003e\n[#45 UserDefaults during testing](https://github.com/Luur/SwiftTips#45-userdefaults-during-testing)\u003cbr /\u003e\n[#44 Additional Info to #38 Protocols: Optional methods](https://github.com/Luur/SwiftTips#44-additional-info-to-38-protocols-optional-methods)\u003cbr /\u003e\n[#43 Responsible view controller for particular view](https://github.com/Luur/SwiftTips#43-responsible-view-controller-for-particular-view)\u003cbr /\u003e\n[#42 Move between textfields](https://github.com/Luur/SwiftTips#42-move-between-textfields)\u003cbr /\u003e\n[#41 Autogenerated `allCases` property for your `enum` (Swift 4.2)](https://github.com/Luur/SwiftTips#41-autogenerated-allcases-property-for-your-enum-swift-42)\u003cbr /\u003e\n[#40 Protocols: Class-only](https://github.com/Luur/SwiftTips#40-protocols-class-only)\u003cbr /\u003e\n[#39 Protocols: Inheritance and composition](https://github.com/Luur/SwiftTips#39-protocols-inheritance-and-composition)\u003cbr /\u003e\n[#38 Protocols: Optional methods](https://github.com/Luur/SwiftTips#38-protocols-optional-methods)\u003cbr /\u003e\n[#37 Protocols: Naming](https://github.com/Luur/SwiftTips#37-protocols-naming)\u003cbr /\u003e\n[#36 Property observers, getter/setter and lazy are mutually exclusive](https://github.com/Luur/SwiftTips#36-property-observers-gettersetter-and-lazy-are-mutually-exclusive)\u003cbr /\u003e\n[#35 Prepare Alamofire standalone functions to unit-testing](https://github.com/Luur/SwiftTips#35-prepare-alamofire-standalone-functions-to-unit-testing)\u003cbr /\u003e\n[#34 Sort array of objects with multiple optional criteria](https://github.com/Luur/SwiftTips#34-sort-array-of-objects-with-multiple-optional-criteria)\u003cbr /\u003e \n[#33 Remove object from array](https://github.com/Luur/SwiftTips#33-remove-object-from-array)\u003cbr /\u003e \n[#32 Delegate naming](https://github.com/Luur/SwiftTips#32-delegate-naming)\u003cbr /\u003e \n[#31 Run, Playground, run!](https://github.com/Luur/SwiftTips#31-run-playground-run)\u003cbr /\u003e \n[#30 `DispatchGroup` usage](https://github.com/Luur/SwiftTips#30-dispatchgroup-usage)\u003cbr /\u003e\n[#29 Remove duplicates](https://github.com/Luur/SwiftTips#29-remove-duplicates)\u003cbr /\u003e\n[#28 Debugging: View Debugging](https://github.com/Luur/SwiftTips#28-debugging-view-debugging)\u003cbr /\u003e\n[#27 Debugging: Breakpoints](https://github.com/Luur/SwiftTips#27-debugging-breakpoints)\u003cbr /\u003e\n[#26 Debugging: Asserts](https://github.com/Luur/SwiftTips#26-debugging-asserts)\u003cbr /\u003e\n[#25 Debugging: Log functions](https://github.com/Luur/SwiftTips#25-debugging-log-functions)\u003cbr /\u003e\n[#24 Update `UIView` content with animation](https://github.com/Luur/SwiftTips#24-update-uiview-content-with-animation)\u003cbr /\u003e\n[#23 Observe MOC changes](https://github.com/Luur/SwiftTips#23-observe-moc-changes)\u003cbr /\u003e\n[#22 Split `String` into words](https://github.com/Luur/SwiftTips#22-split-string-into-words)\u003cbr /\u003e\n[#21 Comparing tuples](https://github.com/Luur/SwiftTips#21-comparing-tuples)\u003cbr /\u003e\n[#20 How to detect that user stop typing](https://github.com/Luur/SwiftTips#20-how-to-detect-that-user-stop-typing)\u003cbr /\u003e\n[#19 Left/rigth text offset inside `UITextField`](https://github.com/Luur/SwiftTips#19-leftrigth-text-offset-inside-uitextfield)\u003cbr /\u003e\n[#18 Common elements in two arrays](https://github.com/Luur/SwiftTips#18-common-elements-in-two-arrays)\u003cbr /\u003e\n[#17 Apply gradient to Navigation Bar](https://github.com/Luur/SwiftTips#17-apply-gradient-to-navigation-bar)\u003cbr /\u003e\n[#16 Get next element of array](https://github.com/Luur/SwiftTips#16-get-next-element-of-array)\u003cbr /\u003e\n[#15 Split array by chunks of given size](https://github.com/Luur/SwiftTips#15-split-array-by-chunks-of-given-size)\u003cbr /\u003e\n[#14 Transparent/Opaque Navigation Bar](https://github.com/Luur/SwiftTips#14-transparentopaque-navigation-bar)\u003cbr /\u003e\n[#13 Group objects by property](https://github.com/Luur/SwiftTips#13-group-objects-by-property)\u003cbr /\u003e\n[#12 Semicolons in Swift](https://github.com/Luur/SwiftTips#12-semicolons-in-swift)\u003cbr /\u003e\n[#11 Fake AppDelegate](https://github.com/Luur/SwiftTips#11-fake-appdelegate)\u003cbr /\u003e\n[#10 Invoke `didSet` when property’s value is set inside `init` context](https://github.com/Luur/SwiftTips#10-invoke-didset-when-propertys-value-is-set-inside-init-context)\u003cbr /\u003e\n[#9 Change type of items in array](https://github.com/Luur/SwiftTips#9-change-type-of-items-in-array)\u003cbr /\u003e\n[#8 `forEach` and `map` execution order difference](https://github.com/Luur/SwiftTips#8-foreach-and-map-execution-order-difference)\u003cbr /\u003e\n[#7 Testing settings](https://github.com/Luur/SwiftTips#7-testing-settings)\u003cbr /\u003e\n[#6 Tips for writing error messages](https://github.com/Luur/SwiftTips#6-tips-for-writing-error-messages)\u003cbr /\u003e\n[#5 Profit to compiler](https://github.com/Luur/SwiftTips#5-profit-to-compiler)\u003cbr /\u003e\n[#4 Combinations of pure functions](https://github.com/Luur/SwiftTips#4-combinations-of-pure-functions)\u003cbr /\u003e\n[#3 Enumerated iteration](https://github.com/Luur/SwiftTips#3-enumerated-iteration)\u003cbr /\u003e\n[#2 Easy way to hide Status Bar](https://github.com/Luur/SwiftTips#2-easy-way-to-hide-status-bar)\u003cbr /\u003e\n[#1 Safe way to return element at specified index](https://github.com/Luur/SwiftTips#1-safe-way-to-return-element-at-specified-index)\u003cbr /\u003e\n\n## [#63 How to make `UIStoryboard` usage safer?]()\n\nBelow I want to show you a few simple ways how to make usage of string literals connected with `UIStoryboard` much more safer.\n\n* **Global constant string literals**\u003cbr /\u003e\nAt first it sounds like a good idea. You only need to define the constant once and it will be available everywhere. Then if you want to change its value, there is only one place in code to change for which the effects will cascade throughout the project.\nBut global constants have some disadvantages. Not as much as global variables but still enought to stop using them. It's not the best practice. I will cover the topic of andvatages and disadavntages of global constants/variables usage in my next posts.\n\n* **Relatable storyboard names**\u003cbr /\u003e\nYour storyboards should be named after the sections of which they cover. It's a general rule. If you have a storyboard which houses view controllers are related to Profile, then the name of that storyboard’s file should be `Profile.storyboard`.\n\n* **Uniform storyboard identifiers**\u003cbr /\u003e\nWhen you want to use `Storyboard Identifiers` on your view controllers, usage of the class names as identifiers will be a good practice. For example, “ProfileViewController” would be the identifier for ProfuleViewController.  Adding this to your naming convention is a good idea.\n\n* **Enum**\u003cbr /\u003e\nTry to consider enums as uniform, centralized global string literal identifiers for 'UIStoryboard'. You can create UIStoryboard class extension which defines all the storyboard files you have in your project. You can also add the convenience initializer or class function to add more syntactic sugar.\n\n```swift\nextension UIStoryboard {\n    enum Storyboard: String {\n        case profile\n        case login\n        \n        var name: String {\n            return rawValue.capitalized\n        }\n    }\n    \n    convenience init(storyboard: Storyboard, bundle: Bundle? = nil) {\n        self.init(name: storyboard.name, bundle: bundle)\n    }\n    // let storyboard = UIStoryboard(storyboard: .profile)\n    \n    class func storyboard(storyboard: Storyboard, bundle: Bundle? = nil) -\u003e UIStoryboard {\n        return UIStoryboard(name: storyboard.name, bundle: bundle)\n    }\n    // let storyboard = UIStoryboard.storyboard(.profile)\n}\n```\nI hope provided solutions will really help you to maintain your storyboards.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#62 \"Massive\" Storyboard]()\n\nI'm prety sure that almost every one has heard about \"main\" MVC problem known as Massive View Controller and how fashionable architectures (MVVM, VIPER, CleanArchitecture) valiantly fight it. But I want to pay attation to not less common problem - massive storyboard. Because of this many developers prefer to make layouts in code insted of storyboard. I've to admit that developers despise storyboards not without reason.\n\nLet's list main storyboard problems:\n\n* Storyboard always become unwieldy and unmanageable.\n\n![](../master/Sources/62/img.png)\n\n* Storyboard is slow. Extremely slow. As it grows in size, it doesn't only become unhandy for developers but also for XCode. Once you tap on a storyboard file of this size, you can leave your seat, grab a cup of coffee and come back. You’ll be lucky if XCode has loaded the storyboard.\n* Merge Conflicts in Source Control. It’s always a painful experience when multiple developers are working on a project as it almost always leads to merge conflicts in storyboard. Merging storyboards is hell because of their nature - storyboards are just hugeass XML files.\n\nInspite of the issues, I'm convinced there is a way to make storyboard great again 🇺🇸, resolving most of the above.\n\n\"A storyboard is meant to explain a story, not a saga.\"\n\nStoryboard can be easily splitted into multiple storyboards, with each one representing an individual story. Yes, it's OK not to have one big, fat, slowloading storyboard file but have 30+ devided storyboards.\n\nAlso don't forget about Storyboard References introduced in iOS 9.\n\n![](../master/Sources/62/img2.png)\n\n**But splitting storyboard will not help with one serious problem.** Storyboard usage has strong coupling with one silent killer known as `String Literals`. Look for the solution in [#63 `StoryboardIdentifiable` protocol]()\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#61 `XCTUnwrap` assertion function]()\n\nIn Xcode 11 new assertion function has been added for use in Swift tests. `XCTUnwrap` asserts that an Optional variable’s value is not `nil`, returning the unwrapped value of expression for subsequent use in the test. It protects you from dealing with conditional chaining for the rest of the test. Also it removes the need to use `XCTAssertNotNil(_:_:file:line:)` with either unwrapping the value. It’s common to unwrap optional before checking it for a particular value so that’s really where `XCTUnwrap()` will come into its own.\n\n```swift\n\nstruct Note {\n    var id: Int\n    var title: String\n    var body: String\n}\n\nclass NotesViewModel {\n\n    static func all() -\u003e [Note] {\n        return [\n            Note(id: 0, title: \"first_note_title\", body: \"first_note_body\"),\n            Note(id: 1, title: \"second_note_title\", body: \"second_note_body\"),\n        ]\n    }\n}\n\n\nfunc testGetFirstNote() throws {\n    let notes = NotesViewModel.all()\n    let firstNote =  try XCTUnwrap(notes.first)\n    XCTAssertEqual(firstNote.title, \"first_note_title\")\n}\n```\n\nThis approach is cleaner than what we might have written previously:\n\n```swift\nfunc testGetFirstNote() {\n    let notes = NotesViewModel.all()\n    if let firstNote = notes.first {\n        XCTAssertEqual(firstNote.title, \"first_note_title\")\n    } else {\n        XCTFail(\"Failed to get first note.\")\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#60 `UITableViewCell` identifier]()\n\n To register or dequeue `UITableViewCell` object we need to provide its string type `identifier`.  Typing string by hand is wasting time and could couse you typos. In this case I would recomend to use extension which declares static `identifier` property inside `UITableViewCell` to avoid these problems.\n \n ```swift\n extension UITableViewCell {\n    static var identifier: String {\n        return String(describing: self)\n    }\n }\n \n let cell = tableView.dequeueReusableCell(withIdentifier: ExampleTableViewCell.identifier)\n tableView.register(ExampleTableViewCell.self, forCellReuseIdentifier: ExampleTableViewCell.identifier)\n \n print(ExampleTableViewCell.identifier) //ExampleTableViewCell\n ```\n \n Back to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#59 `AlertPresentable` protocol](https://twitter.com/szubyak/status/1176760937505837056)\n\nIn my current project I work on I present alerts almost on every view controller. To reduce lines of codes and time spent on duplicate code I created `AlertPresentable` layer and want to share it with you.\nAny `ViewController` which implements `AlertPresentable` protocol receive opportunity to present any type of alerts discribed in this layer just by one line of code.\n\n```swift\nprotocol AlertPresentable {\n    func presentErrorAlert(with message: String)\n    func presentSuccessAlert(with message: String, action: ((UIAlertAction) -\u003e Void)?)\n    func presentConfirmationAlert(with message: String, action: ((UIAlertAction) -\u003e Void)?)\n}\n\nextension AlertPresentable where Self: UIViewController {\n\n    func presentErrorAlert(with message: String) {\n        presentAlert(message: message, actions: [UIAlertAction(title: \"OK\", style: .cancel, handler: nil)])\n    }\n\n    func presentSuccessAlert(with message: String, action: ((UIAlertAction) -\u003e Void)?) {\n        presentAlert(message: message, actions: [UIAlertAction(title: \"OK\", style: .cancel, handler: action)])\n    }\n\n    func presentConfirmationAlert(with message: String, action: ((UIAlertAction) -\u003e Void)?) {\n        presentAlert(message: message, actions: [UIAlertAction(title: \"Yes\", style: .default, handler: action), UIAlertAction(title: \"No\", style: .cancel, handler: nil)])\n    }\n\n    private func presentAlert(title: String? = \"\", message: String? = nil, actions: [UIAlertAction] = []) {\n        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)\n        actions.forEach { (action) in\n            alertController.addAction(action)\n        }\n        present(alertController, animated: true, completion: nil)\n    }\n}\n```\n\nUsage:\n\n```swift\nclass ViewController: UIViewController, AlertPresentable {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        presentErrorAlert(with: \"User not found\")\n\n        presentSuccessAlert(with: \"File downloaded\") { _ in\n            // use downloaded file\n        }\n\n        presentConfirmationAlert(with: \"Are you sure you would like to sign out?\") { _ in\n            // sign out user\n        }\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#58 CollectionView extension for adaptive grid layout](https://twitter.com/szubyak/status/1171870893817180161)\n\nImplementation of grid CollectionView layout is a commont task. But I found that calculation of cell width when you dont know how many cells can fit in one row of CollectionView is not a common task.\n\nHere is my extension for calculation width of cell in grid CollectionView to make your layot adaptive.\n\n```swift\nextension UICollectionView {\n\n    func flexibleCellWidth(minCellWidth: CGFloat, minimumInteritemSpacing: CGFloat) -\u003e CGFloat {\n        let contentWidth = frame.size.width - contentInset.left - contentInset.right\n        let numberOfItemsInRow = Int((contentWidth + minimumInteritemSpacing) / (minCellWidth + minimumInteritemSpacing))\n        let spacesWidth = CGFloat(numberOfItemsInRow - 1) * minimumInteritemSpacing\n        let availableContentWidth = contentWidth - spacesWidth\n        return availableContentWidth / CGFloat(numberOfItemsInRow)\n    }\n}\n```\n\nBased on minimal cell width and minimal interitem spacing it autocalculates number of cells in row and return cell width for the best placement.\n\n```swift\nfunc collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -\u003e CGSize {\n    let cellWidth = collectionView.flexibleCellWidth(minCellWidth: 72, minimumInteritemSpacing: 10)\n    return CGSize(width: cellWidth, height: cellWidth)\n}\n```\n\niPhoneSE   ![](../master/Sources/58/img.png)\n\niPhoneX     ![](../master/Sources/58/img1.png)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#57 Render HTML within a `UILabel`](https://twitter.com/szubyak/status/1171788553665355776)\n\nYou can render HTML strings within a `UILabel` using a special initializer of `NSAttributedString` and passing in `NSAttributedString.DocumentType.html` for `.documentType`. But in most cases it is not enough to display it as is. If we want to add custom font or color we need to use CSS (add CSS header to our HTML string).\n\n```swift\nextension String {\n\n    func htmlAttributedString(with fontName: String, fontSize: Int, colorHex: String) -\u003e NSAttributedString? {\n        do {\n            let cssPrefix = \"\u003cstyle\u003e* { font-family: \\(fontName); color: #\\(colorHex); font-size: \\(fontSize); }\u003c/style\u003e\"\n            let html = cssPrefix + self\n            guard let data = html.data(using: String.Encoding.utf8) else {  return nil }\n            return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)\n        } catch {\n            return nil\n        }\n    }\n}\n```\n\nUsage [example](https://github.com/Luur/SwiftTips/blob/master/Sources/57/example.playground/Contents.swift)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#56 Custom `Error` by adopting `LocalizedError` protocol](https://twitter.com/szubyak/status/1074629447364567040)\n\nCustom errors are an integral parts of you work. Swift-defined error types can provide localized error descriptions by adopting the new `LocalizedError` protocol. \n\n```swift\nenum UserError: Error {\n    case credentialsNotMatch\n    case invalidEmail\n    case invalidName\n}\n\nextension UserError: LocalizedError {\n    public var errorDescription: String? {\n        switch self {\n            case .credentialsNotMatch:\n                return NSLocalizedString(\"Your username and/or password do not match\", comment: \"Credentials do not match\")\n            case .invalidEmail:\n                return NSLocalizedString(\"Please enter email address in format: yourname@example.com\", comment: \"Invalid email format\")\n            case .invalidName:\n                return NSLocalizedString(\"Please enter you name\", comment: \"Name field is blank\")\n        }\n    }\n}\n```\n\nExample:\n\n```swift\nfunc validate(email: String?, password: String?) throws {\n    throw UserError.credentialsNotMatch\n}\n\ndo {\n    try validate(email: \"email\", password: \"password\")\n} catch UserError.credentialsNotMatch {\n    print(UserError.credentialsNotMatch.localizedDescription)\n}\n```\n\nYou can provide even more information. It's common decency to show user except error description also failure reasons and recovery suggestions. Sorry for ambiguous error messages :)\n\n```swift\nenum ProfileError: Error {\n    case invalidSettings\n}\n\nextension ProfileError: LocalizedError {\n    public var errorDescription: String? {\n        switch self {\n            case .invalidSettings:\n                return NSLocalizedString(\"Your profile settings are incorrect\", comment: \"\")\n        }\n    }\n\n    public var failureReason: String? {\n        switch self {\n            case .invalidSettings:\n                return NSLocalizedString(\"I don't know why\", comment: \"\")\n        }\n    }\n    \n    public var recoverySuggestion: String? {\n        switch self {\n            case .invalidSettings:\n                return NSLocalizedString(\"Please provide correct profile settings\", comment: \"\")\n        }\n    }\n}\n\nlet error = ProfileError.invalidSettings\nprint(error.errorDescription)\nprint(error.failureReason)\nprint(error.recoverySuggestion)\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#55 `Result` type without value to provide](https://twitter.com/szubyak/status/1073212384418906112)\n\n`Result` type usage is really popular nowadays.\n\n```swift\nenum Result\u003cT\u003e {\n    case success(result: T)\n    case failure(error: Error)\n}\n\nfunc login(with credentials: Credentials, handler: @escaping (_ result: Result\u003cUser\u003e) -\u003e Void) {\n    // Two possible options:\n    handler(Result.success(result: user))\n    handler(Result.failure(error: UserError.notFound))\n}\n```\n\n`login(with:)` operation has `user` value to provide and default `Result` type fits perfectly here. But let’s imagine that your operation hasn’t got value to provide or you don’t care about it. Default `Result` type makes you to provide the result value any way.\n\n![](../master/Sources/55/img.png)\n\nTo fix this inconvenience you need to add extension and instantiate a generic with an associated value of type `Void`.\n\n```swift\nfunc login(with credentials: Credentials, handler: @escaping (_ result: Result\u003cVoid\u003e) -\u003e Void)\n\nextension Result where T == Void {\n    static var success: Result {\n        return .success(result: ())\n    }\n}\n```\n\nNow we can change our `func login(with:)` a bit, to ignore result success value if we don’t care about it.\n\n```swift\nfunc login(with credentials: Credentials, handler: @escaping (_ result: Result\u003cVoid\u003e) -\u003e Void) {\n    // Two possible options:\n    handler(Result.success)\n    handler(Result.failure(error: UserError.notFound))\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#54 Given, When, Then](https://twitter.com/szubyak/status/1052886769375596545)\n\nIn unit testing terms, there are three phases to a unit test:\n\n* **Given** prepares the **preconditions** for the test. These preconditions include arguments to the function call, states of the subject, and any test doubles that are used to inspect the test subject in subsequent assertions.\n* The **When** phase can be as simple as making the call to the function on the test subject. In the **when** section an operation to be tested is performed.\n* The **Then** phase verifies the actual results against your expected results. These are done with **assertions** statements. An assertion can check if something is true or false, nil or non-nil, two objects match or not.\n\n```swift\nfunc testSum() {\n    // Given\n    let firstValue = 4\n    let secondValue = 3\n    // When\n    let sum = sut.sum(firstValue: firstValue, secondValue: secondValue)\n    // Then\n    XCTAssertEqual(sum, 7)\n}\n```\n\nNote: When comparing two values using `XCTAssertEqual` you should always put the actual value first before the expected value.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#53 `sut` and test lifecycle](https://twitter.com/szubyak/status/1039464769403670529)\n\nThe **subject under test** is always named `sut` . It refers to a subject that is being tested for correct operation. It is short for \"whatever thing we are testing\" and is always defined from the perspective of the test.  So when you look at your tests, there is no ambiguity as to what is being tested. All other objects are named after their types. Clearly identifying the subject under test in the `sut` variable makes it stand out from the rest.\n\nThe **test lifecycle** for each test is surrounded by a pair of functions - `setUp()` and `tearDown()`. The `setUp()` function is called before the execution of each test function in the test class. The `tearDown()` function is called after the execution of each test function in the test class. They provide you a place to prepare the `sut` ready before the test starts, and clean up the `sut` and any states after the test finishes. It’s important that each test starts with the desired initial state.\n\n```swift\nimport XCTest\n\nclass YourClassTests: XCTestCase {\n\n    // MARK: - Subject under test\n    \n    var sut: YourClass!\n    \n    // MARK: - Test lifecycle\n    \n    override func setUp() {\n        super.setUp()\n        sut = YourClass()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#52 Point on circle perimeter](https://twitter.com/szubyak/status/1034785953200726023)\n\nCould be useful solution for positioning nodes in your game or views in ordinary business application on the perimeter of circle.\n\n```swift\nfunc pointOnCircle(radius: Float, center: CGPoint) -\u003e CGPoint {\n    // Random angle between 0 and 2*pi\n    let theta = Float(arc4random_uniform(UInt32.max)) / Float(UInt32.max-1) * .pi * 2.0\n    // Convert polar to cartesian\n    let x = radius * cos(theta)\n    let y = radius * sin(theta)\n    return CGPoint(x: CGFloat(x) + center.x, y: CGFloat(y) + center.y)\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#51 `zip()` function](https://twitter.com/szubyak/status/1032565476143050753)\n\nLet’s imagine you have an array of LOTR heroes, and an array of weapons that match those heros. How could I create a list with the heros and weapons combined at each index? `zip()` function is designed to combine two sequences into a single sequence of tuples. \n\n![](../master/Sources/51/img.png)\n\nNote: I would recomend to wrap the output from `zip()` into array to make its output easier to read.\n\nOne of the useful features of `zip()` is that if your two arrays arent equal in size it will choose the shorter one. Yes, it will not crash your application, just ignore element which doesn’t have a match in second sequence.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#50 `StackView` custom spacing](https://twitter.com/szubyak/status/1031853568586854400)\n\n`StackView`, introduced in iOS 9, made Auto Layout usage much easier, because of reducing the amount of constraints needed to create manually for common layouts. But we faced with the problem, property `spacing` applies equally to the arranged subviews of `StackView`. Before iOS 11, there were 2 ways how to overcome this problem.\nOne way is to create views with desired height and use them as spacer views or we could do it by nesting stack views but these two ways always seemed to be an unnecessary complication.\n\n In iOS 11 you can create stack views with custom spacing between views. But there is no way to specify this custom spacing in Storyboard, only in code.\n \n ```swift\nstackView.setCustomSpacing(32.0, after: label)\n```\n\nAlso, in iOS 11 Apple introduced default and system spacing properties on the `UIStackView` class. You can use these to set or reset the custom spacing after a view.\n\n```swift\nstackview.setCustomSpacing(UIStackView.spacingUseSystem, after: label)\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#49 Named UIColor](https://twitter.com/szubyak/status/1031489173440684032)\n\nXCode 9.0 gives us opportunity to create named colors. We can do it directly inside assets catalog and use it in code and storyboards. Named colors contain 3 parts: name (\"FerrariRed\"), color specified as range and device compatibility.\n\n![](../master/Sources/49/img.png)\n\nCreated named color you can use like this:\n\n```swift\nview.backgroundColor = UIColor(named: \"FerrariRed\")\n```\n\nInside storyboards you can use created named color by selecting it from the color dropdown menu.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#48 `Result` error handling]()\n\nError handling is realy common functionality. But if you want to handle errors across asynchronous boundaries or store value/error results for later processing, then ordinary Swift error handling won’t help. The best alternative is a common pattern called a `Result` type: it stores a value/error “sum” type (either one or the other) and can be used between any two arbitrary execution contexts.\n\nExample of `Result` type:\n\n```swift\nenum Result\u003cT\u003e {\n    case success(result: T)\n    case failure(error: String)\n}\n```\n\nUsage of `Result` type:\n\n```swift\nprotocol TaskStoreProtocol {\n    func fetchTasks(handler: @escaping TaskStoreFetchTasksResult)\n}\n\ntypealias TaskStoreFetchTasksResult = (_ result: Result\u003c[Task]\u003e) -\u003e Void\n\nclass TasksStore: TasksStoreProtocol {\n    \n    func fetchTasks(handler: @escaping TaskStoreFetchTasksResult) {\n        // Some useful code, network request or something like this goes here\n        if success {\n            handler(Result.success(result: fetchedTasks))\n        } else {\n            handler(Result.failure(error: error))\n        }\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#47 Generics: Type parameters]()\n\nHere I want to introduce you with general info about generic type parameters and their naming style. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of angle brackets (such as `\u003cT\u003e`). Once you specify a type parameter, you can use it to define the type of a function’s parameters, or as the function’s return type, or as a type annotation within the body of the function. In each case, the type parameter is replaced with an actual type whenever the function is called.\n\nYou can provide more than one type parameter by writing multiple names within the angle brackets, separated by commas.\n\nIn most cases, type parameters have descriptive names, such as `Key` and `Value` in `Dictionary\u003cKey, Value\u003e` and `Element` in `Array\u003cElement\u003e`, which tells about the relationship between the type parameter and the generic type or function it’s used in. However, when there isn’t a meaningful relationship between them, it’s traditional to name them using single letters such as `T`, `U`, and `V`.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#46 Generics: Basics]()\n\nYou can find usage of generics in several of my tips. So here I want to show you some basics of generics. They are one of the most powerful features of Swift. It gives you opportinity to write flexible, reusable functions. Types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted way.\n\nAt first, here is nongeneric function which swaps two `Int` values:\n```swift\nfunc swapTwoInts(_ a: inout Int, _ b: inout Int) {\n    let temporaryA = a\n    a = b\n    b = temporaryA\n}\n```\nAs you can see, this func is useful but a bit limited, because you can swap only `Int` values. If you want to swap two `String` values, or two `Double` values, you have to write more functions.\n\nGeneric functions can work with any type. Here’s a generic representation of our function.\n```swift\nfunc swapTwoValues\u003cT\u003e(_ a: inout T, _ b: inout T) {\n    let temporaryA = a\n    a = b\n    b = temporaryA\n}\n```\nThe body of our two functions is the same. But the first line of is slightly different. The generic version of the function uses a placeholder type name (called `T`) instead of an actual type name (such as `Int`, `String`, or `Double`). The placeholder type name doesn’t say anything about what `T` must be, but it does say that both `a` and `b` must be of the same type `T`. The actual type to use in place of `T` is determined each time the function is called.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#45 UserDefaults during testing]()\n\nAs with all dependencies, we should reduce `UserDefaults` to an abstract protocol, inject it into the classes that require it, and thereby decouple ourselves from implementation details and increase the testability of our code by introducing seams. But I'll be honest, the `UserDefaults API` is so simple and pervasive that standard dependency management feels like overkill. If so, we've probably encountered the same problem: without the ability to inject mocks, testing code that makes use of `UserDefaults` can be a pain. Any time we use our test device (including running tests on it!) we potentially change the state of its persisted settings.\n\nHere is `extension UserDefaults` that gives your test method an opportunity to run in clean state and not jinx real persisted settings. \n\n```swift\nextension UserDefaults {\n    static func blankDefaultsWhile(handler:()-\u003eVoid){\n        guard let name = Bundle.main.bundleIdentifier else {\n            fatalError(\"Couldn't find bundle ID.\")\n        }\n        let old = UserDefaults.standard.persistentDomain(forName: name)\n        defer {\n            UserDefaults.standard.setPersistentDomain( old ?? [:], forName: name)\n        }\n        UserDefaults.standard.removePersistentDomain(forName: name)\n        handler()\n    }\n}\n```\nUsage: \n\n```swift\nclass MyTests: XCTestCase {\n    func testSomething() {\n        // Defaults can be full of junk.\n        UserDefaults.blankDefaultsWhile {\n            // Some tests that expect clean defaults.\n            // They can also scribble all over defaults with test-specific values.\n        }\n        // Defaults are back to their pre-test state.\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#44 Additional Info to #38 Protocols: Optional methods]()\n\nHere is one more trick how to make protocol method to be optional. Let’s remember why we would like to declare a protocol method as optional? It is because we we don’t want to write the implementation if that method will not be used. So Swift has a feature called extension that allow us to provide a default implementation for those methods that we want to be optional.\n\n```swift\nprotocol CarEngineStatusDelegate {\n    func engineWillStop()\n    func engineDidStop()\n}\n\nextension CarEngineStatusDelegate {\n    func engineWillStop() {}\n}\n```\n\nThis way the class/struct that will use our protocol will only need to implement `func engineDidStop()`.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#43 Responsible view controller for particular view](https://twitter.com/szubyak/status/1015960175247872000)\n\nHow to find the view controller that is responsible for a particular view? This is as easy as walking the responder chain looking for the first `UIViewController` you find.\n\n```swift\nextension UIView {\n    func findViewController() -\u003e UIViewController? {\n        if let nextResponder = self.next as? UIViewController {\n            return nextResponder\n        } else if let nextResponder = self.next as? UIView {\n            return nextResponder.findViewController()\n        } else {\n            return nil \n        }\n    }\n}\n```\n\nYou should only use it when you really need it – if you’re able to call methods directly using a delegate or indirectly by posting notifications then do it in first place.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#42 Move between textfields](https://twitter.com/szubyak/status/1011979216802533376)\n\nLets imagine full of texfields scene (e.g. UserProfile scene). Moving between textfields using Next/Return on on-screen keyboard is integral functionality.\n\n```swift\nfunc textFieldShouldReturn(_ textField: UITextField) -\u003e Bool {\n    let nextTag = textField.tag + 1\n    if let nextResponder = textField.superview?.viewWithTag(nextTag) {\n        nextResponder.becomeFirstResponder()\n    } else {\n        textField.resignFirstResponder()\n    }\n    return true \n}\n```\n\nIf you need to force the first responder to resign itself and aren’t sure which textfield is in control, it’s easier to use `view.endEditing(true)`.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#41 Autogenerated `allCases` property for your `enum` (Swift 4.2)](https://twitter.com/szubyak/status/1008631549888167937)\n\nRetrieving all cases of `enum` is really common task, but it's implementation is not so clean. We were forced to create `static` variable of array with all cases of our `enum` manually.\n\n```swift\nenum Cars {\n    case BMW\n    case Audi\n    case Volkswagen\n    case Mercedes\n\n    static let allCases = [BMW, Audi, Volkswagen, Mercedes]\n}\n```\nIn Swift 4.2 we got really useful property `allCases`, which is autogenerated (all you need to do is make your `enum` conform to the `CaseIterable` protocol), so it releases us from additional steps.\n\n```swift\nenum Cars: CaseIterable {\n    case BMW\n    case Audi\n    case Volkswagen\n    case Mercedes\n}\n\nfor car in Cars.allCases {\n    print(car)\n}\n```\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#40 Protocols: Class-only](https://twitter.com/szubyak/status/1006181062827966465)\u003cbr /\u003e\n\nOne more thing left to say about protocols. Sometimes protocols should be adopted only by classes. To achieve this behaviour you should define you protocol with `class` keyword or by inheriting from `AnyObject`. This is commonly happens because you have a `delegate` property that needs to use `weak` storage to avoid the risk of a `strong reference cycle` (formerly known as a `retain cycle`).\n\n```swift\nweak var delegate: CarDelegate?\n```\nThe `weak` keyword can't be used with structs and enums, because they are value types.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#39 Protocols: Inheritance and composition](https://twitter.com/szubyak/status/1005056393697742849)\u003cbr /\u003e\n\nIn previous tip you can observe how to split your protocol to smaller pieces. Here I will show you how to combine your protocols to make bigger one using inheritance and composition. To merge protocols together  use `\u0026` for protocol composition.\n\n```swift\ntypealias Codable = Decodable \u0026 Encodable\n```\n\nYou can also use protocol inheritance to build larger protocols.\n\n```swift\nprotocol CarEngineStatusDelegate { }\nprotocol CarMovingStatusDelegate { }\nprotocol CarDelegate: CarMovingStatusDelegate, CarEngineStatusDelegate { }\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#38 Protocols: Optional methods](https://twitter.com/szubyak/status/1004694921457086464)\u003cbr /\u003e\n\nIf you implement a protocol in Swift you must implement all its requirements. Optional methods are not allowed.\n\nExample:\n\n```swift\nprotocol CarDelegate {\n    func engineDidStart()\n    func carShouldStartMoving() -\u003e Bool\n    func carDidStartMoving()\n    func engineWillStop()\n    func engineDidStop()\n}\n```\n\nBut there are a few tricks how to make some methods to be optionals:\n* You can split them in two protocols, and adopt only needed one.\n```swift\nprotocol CarMovingStatusDelegate {\n    func carShouldStartMoving() -\u003e Bool\n    func carDidStartMoving()\n}\n\nprotocol CarEngineStatusDelegate {\n    func engineDidStart()\n    func engineWillStop()\n    func engineDidStop()\n}\n```\n* Use the `@objc` attribute on a Swift protocol to receive opportunity to mark methods as being optional, but you may no longer use Swift structs and enums with that protocol, and you may no longer use protocol extensions.\n```swift\n@objc protocol CarDelegate {\n    @objc optional func engineDidStart()\n    func carShouldStartMoving() -\u003e Bool\n    func carDidStartMoving()\n    @objc optional func engineWillStop()\n    @objc optional func engineDidStop()\n}\n```\n\nHere is the optional method usage:\n\n```swift\ndelegate?.engineWillStop?()\n```\n\nThe `delegate` property is optional because there might not be a delegate assigned. And in the `CarDelegate` protocol we made `engineWillStop()` an optional requirement, so even if a delegate is present it might not implement that method.\nAs a result, we need to use optional chaining.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#37 Protocols: Naming](https://twitter.com/szubyak/status/1003204523006021632)\u003cbr /\u003e\n\nIf we are talking about naming the protocol itself:\n* Protocols that describe *what something* is should read as nouns (e.g. `Collection`).\n* Protocols that describe a *capability* should be named using the suffixes `able`, `ible`, or `ing` (e.g. `Equatable`, `ProgressReporting`).\n\nBriefly talking about methods names inside protocol, you can use whatever names you want. But, if your protocol is created to represent delegates please look:  [#32 Delegate naming](https://github.com/Luur/SwiftTips#32-delegate-naming)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#36 Property observers, getter/setter and lazy are mutually exclusive](https://twitter.com/szubyak/status/1001754575857168384)\u003cbr /\u003e\n\nLittle thing that surprisingly became a discovery for me, because it's rare case in practice, so I'm not ashamed of it 🤣. `Property observers`, `getter/setter` and `lazy` cant be used together, they are mutually exclusive. So you should choose what pattern makes most profit to you in particaulr situation.\n\n![](../master/Sources/36/img.png)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#35 Prepare Alamofire standalone functions to unit-testing]()\n\nMethods are functions associated with a type. Mock the type, and you can intercept the method. In Swift, we prefer to do this with protocols. But a standalone function lives on its own, without any associated data. In other words, it has no `self`.\nDuring unit-testing we want to intercept these calls, for two main reasons:\n* To spy on the arguments a function receives.\n* To stub any return values.\n\nIn popular networking 3party library *Almofire* all `request`, `upload` or `download` functions implemented as standalone functions. So, we have dificulties with intercepting during unit testing. We can't mock associated type, because there is no type. Also `responseJSON` function is implemented in extension, so we can't make any changes or override it.\n\nI defined a new class with 2 methods (`request` and `responseJSON`) with the same method signature as Alamofire's `request` and `responseJSON` methods. I called the Alamofire version of  these methods inside. And then used this class as a dependency in my `sut`.\n\n```swift\nimport Alamofire\n\nclass AlamofireWrapper {\n    @discardableResult\n    public func request(_ url: URLConvertible, method: HTTPMethod = .get, parameters: Parameters? = nil, encoding: ParameterEncoding = URLEncoding.default, headers: HTTPHeaders? = nil) -\u003e DataRequest {\n        return Alamofire.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers)\n    }\n\n    public func responseJSON(request: DataRequest, queue: DispatchQueue? = nil, options: JSONSerialization.ReadingOptions = .allowFragments, completionHandler: @escaping (DataResponse\u003cAny\u003e) -\u003e Void) {\n        request.responseJSON(queue: queue, options: options, completionHandler: completionHandler)\n    }\n}\n```\n\nMy request part starts looking like this: \n\n```swift\nvar alamofireWrapper = AlamofireWrapper()\n\nlet request = alamofireWrapper.request(url, parameters: params, encoding: URLEncoding(destination: .queryString))\nalamofireWrapper.responseJSON(request: request) { response in\n    if response.result.isSuccess {\n        success(response.result.value)\n    } else if let error = response.result.error {\n        failure(error)\n    }\n}\n```\n\nAnd here is my test double finaly: \n\n```swift\n// MARK: - Test doubles\n\nclass AlamofireWrapperSpy: AlamofireWrapper {\n\n    enum RequestStatus {\n        case success\n        case failure\n    }\n\n    var status: RequestStatus = .success\n\n    // MARK: Method call expectations\n\n    var requestCalled = false\n    var responseJSONCalled = false\n\n    // MARK: Spied methods\n\n    override func request(_ url: URLConvertible, method: HTTPMethod, parameters: Parameters?, encoding: ParameterEncoding, headers: HTTPHeaders?) -\u003e DataRequest {\n        requestCalled = true\n        return  SessionManager.default.request(\"dummy_url\")\n    }\n\n    override func responseJSON(request: DataRequest, queue: DispatchQueue?, options: JSONSerialization.ReadingOptions, completionHandler: @escaping (DataResponse\u003cAny\u003e) -\u003e Void) {\n        responseJSONCalled = true\n        switch status {\n        case .success:\n            let value = [\"result\": \"best_response_ever\"]\n            completionHandler(DataResponse(request: nil, response: nil, data: nil, result: Result.success(value)))\n        case .failure:\n            let error = NSError(domain: \"\", code: 500, userInfo: nil)\n            completionHandler(DataResponse(request: nil, response: nil, data: nil, result: Result.failure(error)))\n        }\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#34 Sort array of objects with multiple optional criteria](https://twitter.com/szubyak/status/999579540602216448)\n\nFew days ago I faced a sorting task. I needed to sort array of object by more then one criteria that is also optional. My object was `Place` with `rating` and `distance` properties. `rating` was main criteria for sorting and `distance` was secondary. So, here is my workouts.\n\n```swift\n\nstruct Place {\n    var rating: Int?\n    var distance: Double?\n}\n\nfunc sortPlacesByRatingAndDistance(_ places: [Place]) -\u003e [Place] {\n    return places.sorted { t1, t2 in\n        if t1.rating == t2.rating {\n            guard let distance1 = t1.distance, let distance2 = t2.distance else {\n                return false\n            }\n            return distance1 \u003c distance2\n        }\n        guard let rating1 = t1.rating, let rating2 = t2.rating else {\n            return false\n        }\n        return rating1 \u003e rating2\n    }\n}\n\nlet places = [Place(rating: 3, distance: 127), Place(rating: 4, distance: 423), Place(rating: 5, distance: nil), Place(rating: nil, distance: 100), Place(rating: nil, distance: 34), Place(rating: nil, distance: nil)]\n\nlet sortedPlaces = sortPlacesByRatingAndDistance(places) // [{rating 5, nil}, {rating 4, distance 423}, {rating 3, distance 127}, {nil, distance 34}, {nil, distance 100}, {nil, nil}]\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#33 Remove object from array](https://twitter.com/szubyak/status/997471185008021505)\n\nSuper lightweight extension 🎈. How to remove particular object from array. Remove first collection element that is equal to the given `object`.\n\n```swift\nextension Array where Element: Equatable {\n    mutating func remove(_ object: Element) {\n        if let index = index(of: object) {\n            remove(at: index)\n        }\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#32 Delegate naming](https://twitter.com/szubyak/status/997063113659813890)\n\nWhen creating custom delegate methods take into consideration the following list items:\n* You can give the name to  your delegate property `delegate`, if it is just one of them, or put `delegate` at the end, when it is more than one.  Here is the example, `WKWebView` has `uiDelegate` and `navigationDelegate` properties that can point to two different objects. \u2028\n* You should use Apple’s standard approach to avoid verb conjugation. It says that many of your method names will use `will`, `did`, and `should`.\n* Start the name by identifying the class of the object that’s sending the message `func tableView(_ tableView: UITableView,...`. It helps in situations where there is more than one object that can send a message .\n\nAs a result, Apple delegates have a very specific naming convention:\n```swift\nfunc tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents) \n\n## [#31 Run, Playground, run!]()\n\nAsynchronous work in Playground.\n\nTell the playground it should continue running forever, otherwise it will terminate before the asynchronous work has time to hppen.\n\n```swift\nPlaygroundPage.current.needsIndefiniteExecution = true\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#30 `DispatchGroup` usage]()\n\nLet’s say you’ve got several long running tasks to perform. After all of them have finished, you’d like to run some further logic. You could run each task in a sequential fashion, but that isn’t so efficient - you’d really like the former tasks to run concurrently. `DispatchGroup` enables you to do exactly this.\n\n```swift\nlet dispatchGroup = DispatchGroup()\n\nfor i in 1...5 {\n    dispatchGroup.enter()\n    Alamofire.request(url, parameters: params).responseJSON { response in\n        //work with response\n        dispatchGroup.leave() \n    }\n}\n\ndispatchGroup.notify(queue: .main) {\n    print(\"All requests complete\")\n}\n```\n\nIn the above, all long running functions will perform concurrently, followed by the print statement, which will execute on the main thread. \n\nEach call to `enter()` must be matched later on with a call to `leave()`, after which the group will call the closure provided to `notify()`. \n\n`DispatchGroup` has a few other tricks:\n* Instead of `notify()`, we can call `wait()`. This blocks the current thread until the group’s tasks have completed.\n* A further option is `wait(timeout:)`. This blocks the current thread, but after the timeout specified, continues anyway. To create a timeout object of type `DispatchTime`, the syntax `.now() + 1` will create a timeout one second from now.\n* `wait(timeout:)` returns an enum that can be used to determine whether the group completed, or timed out.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#29 Remove duplicates](https://twitter.com/szubyak/status/993399930457939968)\n\nClear way 🛣️ to return the unique list of objects based on a given key 🔑. It has the advantage of not requiring the Hashable and being able to return an unique list based on any field or combination.\n\n```swift\nextension Array {\n    func unique\u003cT:Hashable\u003e(map: ((Element) -\u003e (T)))  -\u003e [Element] {\n        var set: Set\u003cT\u003e = []\n        var arrayOrdered: [Element] = []\n        for value in self {\n            if !set.contains(map(value)) {\n                set.insert(map(value))\n                arrayOrdered.append(value)\n            }   \n        }\n        return arrayOrdered\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#28 Debugging: View Debugging](https://twitter.com/szubyak/status/992667725574045696)\n\nUsing `View Debugging` you’re now able to inspect an entire view hierarchy visually – right from within Xcode, instead of printing frames to the console and trying to visualize layouts in your head.\n\n![](../master/Sources/28/img1.png)\n\nYou can invoke the view debugger by choosing `View UI Hierarchy` from the process view options menu in the debug navigator, or by choosing `Debug` \u003e `View Debugging` \u003e `Capture View Hierarchy`.\n\n![](../master/Sources/28/img2.png)\n\nYou'll see a 3D representation of your view, which means you can look behind the layers to see what else is there. The hierarchy automatically puts some depth between each of its views, so they appear to pop off the canvas as you rotate them.\nIf you have a complicated view layout, `View Debugging` \u003e `Show View Frames` option will draw lines around all your views so you can see exactly where they are.\n\nMore about view debugging [here](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/special_debugging_workflows.html)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#27 Debugging: Breakpoints](https://twitter.com/szubyak/status/989442320260108288)\n\nA `breakpoint` is a debugging tool that allows you to pause the execution of your program up to a certain moment. Creating `pause` points in your code can help you investigate your code.\nWhile your app is paused, light green arrow that shows your current execution position can be moved. Just click and drag it somewhere else to have execution pick up from there – although Xcode will warn you that it might have unexpected results, so tread carefully!\n\nRight-click on the breakpoint (the blue arrow marker) and choose Edit Breakpoint.\n\n![](../master/Sources/27/img1.png)\n\nIn the popup that appears you can set the `condition`. Execution will now pause only when your condition is true. You can use conditional breakpoints to execute debugger commands automatically – the `Automatically continue` checkbox is perfect for making your program continue uninterrupted while breakpoints silently trigger actions.\nAlso you can set `Ignore times before stoping` and actions like `Debuger command`, `Log message`, `Sound`, etc.\n\n![](../master/Sources/27/img2.png)\n\nShortcuts:\n\n`F6`- Step Over.\n`Ctrl+Cmd+Y` - Continue (continue executing my program until you hit another breakpoint)\n\nIn Xcode debug console you can use `po` to print what you need during pause.\n\n![](../master/Sources/27/img3.png)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#26 Debugging: Asserts](https://twitter.com/szubyak/status/989153864472547328)\n\n`assert()` is debug-only check that will force your app to crash if specific condition is false. \n\n```swift\nassert(4 == 4, \"Maths error\") //OK\nassert(3 == 2, \"Maths error\") //Crash\n```\nAs you can see `assert()` takes two parameters: \n* Something to check.\n* Message to print out of the check fails. \n    \nIf the check evaluates to false, your app will be forced to crash because you know it's not in a safe state, and you'll see the error message in the debug console.\nIf you don’t have a condition to evaluate, or don’t need to evaluate one, you can use `assertionFailure()` function.\n\n`precondition()` is not debug-only check. It will crash your app even in release mode.\n\n```swift\nprecondition(4 == 4, \"Maths error\") //OK\nprecondition(3 == 2, \"Maths error\") //Crash\n```\n`preconditionFailure()` works the same as `assertionFailure()`. With the same difference as above, it works for release builds. \n\n`fatalError()`, like `assertionFailure()` and `preconditionFailure()` works for all optimisation levels in all build configurations.\n\n```swift\nfatalError(\"ERROR\")\n```\n\nMore about asserts and optimisation levels you can find [here](https://agostini.tech/2017/10/01/assert-precondition-and-fatal-error-in-swift/)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#25 Debugging: Log functions](https://twitter.com/szubyak/status/988328809681342464) \n\nDebuging 👨‍🔧 is one of the most importent aspects of programing👨‍💻. It should be in your skillbox anyway. It contains  log functions, asserts, breakpoints and view debuging.\nLet's observe everyone of them just one by one. And here are log functions in the crosshairs 🔍.\n\nWe know `print()` as a variadic function. Function that accepts any number of parameters. \n\n```swift\nprint(\"one\", \"two\", \"three\", \"four\") //one two three four\n```\n\nBut it's variadic nature becomes much more useful when you use `separator` and `terminator`, its optional extra parameters. `separator` gives you opportunity to provide a string that should be placed between every item. It's \"space\" by default.\n\n```swift\nprint(\"one\", \"two\", \"three\", \"four\", separator: \"-\") //one-two-three-four\n```\n\nMeanwhile `terminator` is what should be placed after the last item.\nIt’s `\\n` by default, which means \"line break\".\n\n```swift\nprint(\"one\", \"two\", \"three\", \"four\", terminator: \" five\") //one two three four five\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#24 Update `UIView` content with animation](https://twitter.com/szubyak/status/985434399138304000)\n\nReally lightweight way 🎈 How to add content changing animation to UIView and it subclasses.\n\n```swift\nextension UIView {\n    func fadeTransition(_ duration: CFTimeInterval) {\n        let animation = CATransition()\n        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)\n        animation.type = kCATransitionFade\n        animation.duration = duration\n        layer.add(animation, forKey: kCATransitionFade)\n    }\n}\n```\nJust invoke 🧙‍♂️ `fadeTransition(_ duration: CFTimeInterval)` by your view before you will apply a change.\n\n```swift\nlabel.fadeTransition(1)\nlabel.text = \"Updated test content with animation\"\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#23 Observe MOC changes](https://twitter.com/szubyak/status/983647253234626560)\n\nNext code snippet 📃 I use to keep eye on changes that take place in the managed object context. Useful thing to know what's going on, what was added, updated ( what specific values were changed ) or deleted 📥📝📤\n\n```swift\nfunc changeNotification(_ notification: Notification) {\n    guard let userInfo = notification.userInfo else { return }\n\n    if let inserts = userInfo[NSInsertedObjectsKey] as? Set\u003cNSManagedObject\u003e, inserts.count \u003e 0 {\n        print(\"--- INSERTS ---\")\n        print(inserts)\n        print(\"+++++++++++++++\")\n    }\n\n    if let updates = userInfo[NSUpdatedObjectsKey] as? Set\u003cNSManagedObject\u003e, updates.count \u003e 0 {\n        print(\"--- UPDATES ---\")\n        for update in updates {\n            print(update.changedValues())\n        }\n        print(\"+++++++++++++++\")\n    }\n\n    if let deletes = userInfo[NSDeletedObjectsKey] as? Set\u003cNSManagedObject\u003e, deletes.count \u003e 0 {\n        print(\"--- DELETES ---\")\n        print(deletes)\n        print(\"+++++++++++++++\")\n    }\n}\n\nNotificationCenter.default.addObserver(self, selector: #selector(self.changeNotification(_:)), name: .NSManagedObjectContextObjectsDidChange, object: moc)\n```\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#22 Split `String` into words](https://twitter.com/szubyak/status/981833649296498689)\n\nDefault ways of splitting ✂️ `String` don't work perfect sometimes, because of punctuation characters and other \"wreckers\" 🐛. Here is extension for splitting ✂️ `String` into words 💻🧐👌.\n\n```swift\nextension String {\n    var words: [String] {\n        return components(separatedBy: .punctuationCharacters)\n            .joined()\n            .components(separatedBy: .whitespaces)\n            .filter{!$0.isEmpty}\n    }\n}\n```\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#21 Comparing tuples](https://twitter.com/szubyak/status/980119909387599873)\n\nI discovered strange behavior of tuples during comparing 🤪. Comparison cares only about types and ignores labels 😦. So result can be unexpected. Be careful ⚠️. \n\n```swift\nlet car = (model: \"Tesla\", producer: \"USA\")\nlet company = (name: \"Tesla\", country: \"USA\")\nif car == company {\n    print(\"Equal\")\n} else {\n    print(\"Not equal\")\n}\n```\nPrinted result will be: `Equal`\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#20 How to detect that user stop typing](https://twitter.com/szubyak/status/978659051893555201)\n\nPainless way ( NO to timers from now ⛔️ ) how to detect that user stop typing text in text field ⌨️ Could be usefull for lifetime search 🔍\n\n```swift\nclass TestViewController: UIViewController {\n\n    @objc func searchBarDidEndTyping(_ textField: UISearchBar) {\n        print(\"User finsihed typing text in search bar\")\n    }\n\n    @objc func textFieldDidEndTyping(_ textField: UITextField) {\n        print(\"User finished typing text in text field\")\n    }\n}\n\nextension TestViewController: UISearchBarDelegate {\n    func searchBar(_ searchBar: UISearchBar, shouldChangeTextIn range: NSRange, replacementText text: String) -\u003e Bool {\n        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchBarDidEndTyping), object: searchBar)\n        self.perform(#selector(searchBarDidEndTyping), with: searchBar, afterDelay: 0.5)\n        return true\n    }\n}\n\nextension TestViewController: UITextFieldDelegate {\n    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -\u003e Bool {\n        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(textFieldDidEndTyping), object: textField)\n        self.perform(#selector(textFieldDidEndTyping), with: textField, afterDelay: 0.5)\n        return true\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#19 Left/rigth text offset inside `UITextField`](https://twitter.com/szubyak/status/976547738908323840)\n\nClear way of adding left\\right text offset inside `UItextField` 🔨🧐💻  Also, because of `@IBInspectable` it could be easily editable in Interface Builder’s inspector panel.\n\n```swift\n@IBDesignable\nextension UITextField {\n\n    @IBInspectable var leftPaddingWidth: CGFloat {\n        get {\n            return leftView!.frame.size.width\n        }\n        set {\n            let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))\n            leftView = paddingView\n            leftViewMode = .always\n        }\n    }\n\n    @IBInspectable var rigthPaddingWidth: CGFloat {\n        get {\n            return rightView!.frame.size.width\n        }\n        set {\n            let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))\n            rightView = paddingView\n            rightViewMode = .always\n        }\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#18 Common elements in two arrays](https://twitter.com/szubyak/status/975736596661178369)\n\nI'm not huge fan of custom operators 😐 because they are intuitively obvious only to their authors, but I've created one which gives you opportunity to get common elements in two arrays whos elements implement `Equatable` protocol 🔨🧐💻\n\n```swift\ninfix operator \u0026\nfunc  \u0026\u003cT : Equatable\u003e(lhs: [T], rhs: [T]) -\u003e [T] {\n    return lhs.filter { rhs.contains($0) }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#17 Apply gradient to Navigation Bar](https://twitter.com/szubyak/status/974580828750704641)\n\nGradient 🏳️‍🌈 on Navigation Bar is really good looking, but not very easy to implement 🧐🔨👨‍💻\nWorks with iOS 11 largeTitle navigation bar too 👌\n\n```swift\nstruct GradientComponents {\n    var colors: [CGColor]\n    var locations: [NSNumber]\n    var startPoint: CGPoint\n    var endPoint: CGPoint\n}\n\nextension UINavigationBar {\n\n    func applyNavigationBarGradient(with components: GradientComponents) {\n\n        let size = CGSize(width: UIScreen.main.bounds.size.width, height: 1)\n        let gradient = CAGradientLayer()\n        gradient.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)\n\n        gradient.colors = components.colors\n        gradient.locations = components.locations\n        gradient.startPoint = components.startPoint\n        gradient.endPoint = components.endPoint\n\n        UIGraphicsBeginImageContext(gradient.bounds.size)\n        gradient.render(in: UIGraphicsGetCurrentContext()!)\n        let image = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        self.barTintColor = UIColor(patternImage: image!)\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#16 Get next element of array](https://twitter.com/szubyak/status/973146709030207489)\n\nEasy way how to get next element of array\n\n```swift\nextension Array where Element: Hashable {\n    func after(item: Element) -\u003e Element? {\n        if let index = self.index(of: item), index + 1 \u003c self.count {\n            return self[index + 1]\n        }\n        return nil\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#15 Split array by chunks of given size](https://twitter.com/szubyak/status/971351860820037632)\n\nGreat extension to split array by chunks of given size\n\n```swift\nextension Array {\n    func chunk(_ chunkSize: Int) -\u003e [[Element]] {\n        return stride(from: 0, to: self.count, by: chunkSize).map({ (startIndex) -\u003e [Element] in\n            let endIndex = (startIndex.advanced(by: chunkSize) \u003e self.count) ? self.count-startIndex : chunkSize\n            return Array(self[startIndex..\u003cstartIndex.advanced(by: endIndex)])\n        })\n    }\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#14 Transparent/Opaque Navigation Bar](https://twitter.com/szubyak/status/970962096245628929)\nScene with `UIImageView` on top looks stylish if navigation bar is transparent.\nEasy way how to make navigation bar transparent or opaque.\n\n```swift\nfunc transparentNavigationBar() {\n    self.setBackgroundImage(UIImage(), for: .default)\n    self.shadowImage = UIImage()\n}\n\nfunc opaqueNavigationBar() {\n    self.shadowImage = nil\n    self.setBackgroundImage(nil, for: .default)\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#13 Group objects by property](https://twitter.com/szubyak/status/966248375988490240)\n\nOne more useful extension 🔨💻 Gives you opportunity to group objects by property 👨‍💻🧐\n\n```swift\nextension Sequence {\n    func group\u003cGroupingType: Hashable\u003e(by key: (Iterator.Element) -\u003e GroupingType) -\u003e [[Iterator.Element]] {\n        var groups: [GroupingType: [Iterator.Element]] = [:]\n        var groupsOrder: [GroupingType] = []\n        forEach { element in\n            let key = key(element)\n            if case nil = groups[key]?.append(element) {\n                groups[key] = [element]\n                groupsOrder.append(key)\n            }\n        }\n        return groupsOrder.map { groups[$0]! }\n    }\n}\n```\n\nUsage:\n\n```swift\nstruct Person {\n    var name: String\n    var age: Int\n}\n\nlet mike = Person(name: \"Mike\", age: 18)\nlet john = Person(name: \"John\", age: 18)\nlet bob = Person(name: \"Bob\", age: 56)\nlet jake = Person(name: \"Jake\", age: 56)\nlet roman = Person(name: \"Roman\", age: 25)\n\nlet persons = [mike, john, bob, jake, roman]\n\nlet groupedPersons = persons.group { $0.age }\n\nfor persons in groupedPersons {\n    print(persons.map { $0.name })\n}\n```\n\nResult:\n\n```\n[\"Mike\", \"John\"]\n[\"Bob\", \"Jake\"]\n[\"Roman\"]\n```\n\nAlso in-box [alternative](https://developer.apple.com/documentation/swift/dictionary/2919592-init)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#12 Semicolons in Swift](https://twitter.com/szubyak/status/963144748004454400)\n\nDo you need semicolons in Swift ? Short answer is NO, but you can use them and it will give you interesting opportunity. Semicolons enable you to join related components into a single line.\n\n```swift\nfunc sum(a: Int, b: Int) -\u003e Int {\n    let sum = a + b; return sum\n}\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#11 Fake AppDelegate](https://twitter.com/szubyak/status/963013740265385984)\n\nUnit testing shouldn’t have any side effects. While running tests, Xcode firstly launches app and thus having the side effect of executing any code we may have in our App Delegate and initial View Controller. Fake AppDelegate in your `main.swift` to prevent it.\n\nYou can find `main.swift` file [here](../master/Sources/11/main.swift)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#10 Invoke `didSet` when property’s value is set inside `init` context](https://twitter.com/szubyak/status/961707655105531905)\n\nApple's docs specify that: \"Property observers are only called when the property’s value is set outside of initialization context.\"\n\n`defer` can change situation 😊\n\n```swift\nclass AA {\n    var propertyAA: String! {\n        didSet {\n            print(\"Function: \\(#function)\")\n        }\n    }\n\n    init(propertyAA: String) {\n        self.propertyAA = propertyAA\n    }\n}\n\nclass BB {\n    var propertyBB: String! {\n        didSet {\n            print(\"Function: \\(#function)\")\n        }\n    }\n\n    init(propertyBB: String) {\n        defer {\n            self.propertyBB = propertyBB\n        }\n    }\n}\n\nlet aa = AA(propertyAA: \"aa\")\nlet bb = BB(propertyBB: \"bb\")\n```\nResult:\n\n```\nFunction: propertyBB\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#9 Change type of items in array](https://twitter.com/szubyak/status/956544356370059265)\n\nTwo ways of changing type of items in array and obvious difference between them 🧐👨‍💻\n\n```swift\nlet numbers = [\"1\", \"2\", \"3\", \"4\", \"notInt\"]\nlet mapNumbers = numbers.map { Int($0) }  // [Optional(1), Optional(2), Optional(3), Optional(4), nil]\nlet compactNumbers = numbers.compactMap { Int($0) } // [1, 2, 3, 4]\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#8 `forEach` and `map` execution order difference](https://twitter.com/szubyak/status/956538549444186112)\n\nExecution order is interesting difference between `forEach` and `map`: `forEach` is guaranteed to go through array elements in its sequence, while `map` is free to go in any order.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#7 Testing settings](https://twitter.com/szubyak/status/955468985121886208)\n\n1) Even if you don't write UI Tests, they still take considerable amount of time to run. Just skip it.\n2) Enable code coverage stats in Xcode, it helps to find which method was tested, not tested, partly tested. But don’t pay too much attention to the percentage 😊.\n\n![](../master/Sources/7/img.jpeg)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#6 Tips for writing error messages](https://twitter.com/szubyak/status/955054366419013632)\n\n1) Say what happened and why\n2) Suggest a next step\n3) Find the right tone (If it’s a stressful or serious issue, then a silly tone would be inappropriate)\n\n[Common​ ​Types​ ​of​ ​Error​ ​Messages](../master/Sources/6/Common​​Error​​Messages.pdf)\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#5 Profit to compiler](https://twitter.com/szubyak/status/954329152160780288)\n\nDo you know that using `map` gives profit to the compiler: it's now clear we want to apply some code to every item in an array, then like in `for` loop we could have `break` on halfway through.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#4 Combinations of pure functions](https://twitter.com/szubyak/status/953993641391017984)\n\n`compactMap` func is effectively the combination of using `map` and `joined` in a single call, in that order. It maps items in array A into array B using a func you provide, then joins the results using concatenation.\n\nFunctions `min` and `max` could be also combinations of `sorted.first` and `sorted.last` in single call.\n\n```swift\nlet colors = [\"red\", \"blue\", \"black\", \"white\"]\n\nlet min = colors.min() // black\nlet first = colors.sorted().first // black\n\nlet max = colors.max() // white\nlet last = colors.sorted().last // white\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#3 Enumerated iteration](https://twitter.com/szubyak/status/951039299759362048)\n\nUse `enumerated` when you iterate over the collection to return a sequence of pairs `(n, c)`, where `n` - index for each element and `c` - its value 👨‍💻💻\n```swift\nfor (n, c) in \"Swift\".enumerated() {\n    print(\"\\(n): \\(c)\")\n}\n```\nResult:\n\n```\n0: S\n1: w\n2: i\n3: f\n4: t\n```\n\nAlso be careful with this tricky thing, `enumerated` on collection will not provide actual indices, but monotonically increasing integer, which happens to be the same as the index for Array but not for anything else, especially slices.\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#2 Easy way to hide Status Bar](https://twitter.com/szubyak/status/950687583222337537)\n\nEver faced the problem that u can't hide status bar because of `prefersStatusBarHidden` is `get-only`? The simplest solution is to `override` it 🧐👨‍💻\n\n```swift\nlet vc = UIViewController()\nvc.prefersStatusBarHidden = true // error\nprint(\"statusBarHidded \\(vc.prefersStatusBarHidden)\") // false\n\nclass TestViewController: UIViewController {\n    override var prefersStatusBarHidden: Bool {\n        return true\n    }\n}\n\nlet testVC = TestViewController()\nprint(\"statusBarHidded \\(testVC.prefersStatusBarHidden)\") // true\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n\n## [#1 Safe way to return element at specified index](https://twitter.com/szubyak/status/950345927054778368)\n\nYou can extend collections to return the element at the specified index if it is within bounds, otherwise nil.\n\n```swift\nextension Collection {\n    subscript (safe index: Index) -\u003e Element? {\n        return indices.contains(index) ? self[index] : nil\n    }\n}\n\nlet cars = [\"Lexus\", \"Ford\", \"Volvo\", \"Toyota\", \"Opel\"]\nlet selectedCar1 = cars[safe: 3] // Toyota\nlet selectedCar2 = cars[safe: 6] // not crash, but nil\n```\n\nBack to [Top](https://github.com/Luur/SwiftTips#-table-of-contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLuur%2FSwiftEchoes-Tips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLuur%2FSwiftEchoes-Tips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLuur%2FSwiftEchoes-Tips/lists"}