RxSwift - Reactive Programming with Swift RxSwift: Reactive Programming with Swift By Junior Bontognali, Scott Gardner, Shai Mishali, Florent Pillet & Marin Todorov Copyright ©2020 Razeware LLC. Notice of Rights All rights reserved. No part of this book or corresponding materials (such as text, images, or source code) may be reproduced or distributed by any means without prior written permission of the copyright owner. Notice of Liability This book and all corresponding materials (such as source code) are provided on an “as is” basis, without warranty of any kind, express of implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in action of contract, tort or otherwise, arising from, out of or in connection with the software or the use of other dealing in the software. Trademarks All trademarks and registered trademarks appearing in this book are the property of their own respective owners. raywenderlich.com 2 RxSwift - Reactive Programming with Swift Dedications "To my father. To my mom. To Mirjam and our beautiful daughter." — Marin Todorov "For Fabienne, Alexandra, and all the rabbits." — Florent Pillet "For Elia and Baby Ethan. To my father and mother." — Shai Mishali "For Charlotte" — Scott Gardner raywenderlich.com 3 RxSwift - Reactive Programming with Swift About the Authors Florent Pillet is an author of this book. Florent has been developing for mobile platforms since the last century and moved to iOS on day 1. He adopted reactive programming before Swift was announced and has been using RxSwift in production since 2015. A freelance developer, Florent also uses Rx on Android and likes working on tools for developers like the popular NSLogger when he's not contracting for clients worldwide. Say hello to Florent on Twitter at @fpillet. Shai Mishali is an author and the final pass editor on this book. He's the iOS Tech Lead for Gett, the global on-demand mobility company; as well as an international speaker, a multi-book author and editor, and a highly active open-source contributor and maintainer on several high-profile projects - namely, the RxSwift Community and RxSwift projects, but also releases many open- source endeavors around Combine such as CombineCocoa, RxCombine and more. As an avid enthusiast of hackathons, Shai took 1st place at BattleHack Tel-Aviv 2014, BattleHack World Finals San Jose 2014, and Ford's Developer Challenge Tel-Aviv 2015. You can find him on GitHub and Twitter as @freak4pc. Marin Todorov is an author of this book. Marin is one of the founding members of the raywenderlich.com team and has worked on eight of the team's books. Besides crafting code, Marin also enjoys blogging, teaching, and speaking at conferences. He happily open-sources code. You can find out more about Marin at www.underplot.com. Scott Gardner is an author of this book. Scott is a veteran iOS app architect and developer with over ten years of experience. He's authored several books, video courses, tutorials, and articles on Swift, RxSwift, and iOS app development. Additionally, Scott is an Apple Certified Trainer for Swift and iOS, and he also enjoys speaking at conferences, meetups, and online events. Say hello to Scott on Twitter at @scotteg. raywenderlich.com 4 RxSwift - Reactive Programming with Swift About the Artist Vicki Wenderlich is the designer and artist of the cover of this book. She is Ray’s wife and business partner. She is a digital artist who creates illustrations, game art and a lot of other art or design work for the tutorials and books on raywenderlich.com. When she’s not making art, she loves hiking, a good glass of wine and attempting to create the perfect cheese plate. raywenderlich.com 5 RxSwift - Reactive Programming with Swift Table of Contents: Overview Acknowledgements............................................................................... 16 Introduction.............................................................................................. 17 Book Updates........................................................................................... 21 Book License............................................................................................. 22 What You Need........................................................................................ 23 Section I: Getting Started with RxSwift...................... 24 Chapter 1: Hello, RxSwift!...................................................... 25 Chapter 2: Observables........................................................... 48 Chapter 3: Subjects.................................................................... 72 Chapter 4: Observables & Subjects in Practice.............. 90 Section II: Operators & Best Practices...................... 112 Chapter 5: Filtering Operators........................................... 114 Chapter 6: Filtering Operators in Practice.................... 134 Chapter 7: Transforming Operators................................. 157 Chapter 8: Transforming Operators in Practice.......... 174 Chapter 9: Combining Operators...................................... 195 Chapter 10: Combining Operators in Practice............ 217 Chapter 11: Time-Based Operators................................. 240 Section III: iOS Apps with RxCocoa........................... 261 Chapter 12: Beginning RxCocoa........................................ 262 Chapter 13: Intermediate RxCocoa................................. 285 raywenderlich.com 6 RxSwift - Reactive Programming with Swift Section IV: Intermediate RxSwift/RxCocoa ........... 310 Chapter 14: Error Handling in Practice.......................... 311 Chapter 15: Intro to Schedulers........................................ 332 Chapter 16: Testing with RxTest........................................ 348 Chapter 17: Creating Custom Reactive Extensions.. 365 Section V: RxSwift Community Cookbook.............. 383 Chapter 18: Table & Collection Views............................. 384 Chapter 19: RxSwiftExt......................................................... 389 Chapter 20: Action.................................................................. 394 Chapter 21: RxGesture.......................................................... 399 Chapter 22: Debugging with RxTimelane...................... 404 Chapter 23: RxAlamofire...................................................... 411 Section VI: Putting It All Together ............................. 416 Chapter 24: MVVM with RxSwift...................................... 417 Chapter 25: Building a Complete RxSwift App............ 442 Conclusion.............................................................................................. 471 raywenderlich.com 7 RxSwift - Reactive Programming with Swift Table of Contents: Extended Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Who this book is for. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 How to use this book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 What’s in store. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Book Updates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Book License. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 What You Need . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Section I: Getting Started with RxSwift . . . . . . . . . . . . 24 Chapter 1: Hello, RxSwift! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Introduction to asynchronous programming. . . . . . . . . . . . . . . . . . . . . . . . . 26 Foundation of RxSwift. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 App architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 RxCocoa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Installing RxSwift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 RxSwift and Combine. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Community . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Where to go from here?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Chapter 2: Observables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 What is an observable? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Lifecycle of an observable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Creating observables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Subscribing to observables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Disposing and terminating. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Creating observable factories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 raywenderlich.com 8 RxSwift - Reactive Programming with Swift Using Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Chapter 3: Subjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 What are subjects?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Working with publish subjects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Working with behavior subjects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Working with replay subjects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Working with relays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Chapter 4: Observables & Subjects in Practice. . . . . . . . . . . . . . 90 Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Using a subject/relay in a view controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Talking to other view controllers via subjects . . . . . . . . . . . . . . . . . . . . . . . . 97 Creating a custom observable. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 RxSwift traits in practice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Completable. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Challenges. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Section II: Operators & Best Practices. . . . . . . . . . . . 112 Chapter 5: Filtering Operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Getting started. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Ignoring operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Skipping operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Taking operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Distinct operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Challenge. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Chapter 6: Filtering Operators in Practice . . . . . . . . . . . . . . . . . 134 Improving the Combinestagram project . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Sharing subscriptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 raywenderlich.com 9 RxSwift - Reactive Programming with Swift Improving the photo selector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Trying out time-based filter operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Challenge. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Chapter 7: Transforming Operators. . . . . . . . . . . . . . . . . . . . . . . . 157 Getting started. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Transforming elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Transforming inner observables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Observing events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Challenge. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Chapter 8: Transforming Operators in Practice. . . . . . . . . . . . 174 Getting started with GitFeed. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Fetching data from the web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Transforming the response. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Persisting objects to disk. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Add a last-modified header to the request. . . . . . . . . . . . . . . . . . . . . . . . . . 187 Challenge. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Chapter 9: Combining Operators . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Getting started. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Prefixing and concatenating. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 Merging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Combining elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Triggers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Switches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Combining elements within a sequence. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Challenge. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Chapter 10: Combining Operators in Practice . . . . . . . . . . . . . 217 Getting started. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Preparing the web backend service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Categories view controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Adding the event download service. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224 raywenderlich.com 10