100% found this document useful (1 vote)
8 views69 pages

Combine Asynchronous Programming With Swift First Edition Tutorial Team pdf download

Ebook installation

Uploaded by

annakytomino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
8 views69 pages

Combine Asynchronous Programming With Swift First Edition Tutorial Team pdf download

Ebook installation

Uploaded by

annakytomino
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 69

Combine Asynchronous Programming With Swift

First Edition Tutorial Team download

https://ebookbell.com/product/combine-asynchronous-programming-
with-swift-first-edition-tutorial-team-38411528

Explore and download more ebooks at ebookbell.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

Combine Asynchronous Programming With Swift First Edition Scott


Gardner

https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-first-edition-scott-gardner-11711318

Combine Asynchronous Programming With Swift 2nd Edition Scott Gardner

https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-2nd-edition-scott-gardner-36336544

Combine Asynchronous Programming With Swift Third Edition 3rd Edition


Scott Gardner

https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-third-edition-3rd-edition-scott-gardner-36336580

Combine Asynchronous Programming With Swift Marin Todorov Scott


Gardner Shai Mishali Florent Pillet

https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-marin-todorov-scott-gardner-shai-mishali-florent-pillet-38451828
Combine Asynchronous Programming With Swift 1st Edition Scott Gardner

https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-1st-edition-scott-gardner-10598924

Asynchronous Programming With Swiftui And Combine 1st Peter Friese

https://ebookbell.com/product/asynchronous-programming-with-swiftui-
and-combine-1st-peter-friese-47531966

Combine Or Combust Cooperating On Chemicals And Hazardous Substances


Management Asiaeurope Foundation

https://ebookbell.com/product/combine-or-combust-cooperating-on-
chemicals-and-hazardous-substances-management-asiaeurope-
foundation-2428176

Combine Harvesters Theory Modeling And Design Miu Petre

https://ebookbell.com/product/combine-harvesters-theory-modeling-and-
design-miu-petre-5264472

Combine Mastery In Swiftui Mark Moeykens

https://ebookbell.com/product/combine-mastery-in-swiftui-mark-
moeykens-54302816
Combine

Combine: Asynchronous Programming with


Swift
By Scott Gardner, Shai Mishali, Florent Pillet & Marin Todorov

Copyright ©2019 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
Combine

Table of Contents: Overview


About the Cover ...................................................................................... 12
What You Need ........................................................................................ 16
Book License ............................................................................................. 17
Book Source Code & Forums ............................................................. 18
Section I: Introduction to Combine .............................. 20
Chapter 1: Hello, Combine! .................................................... 21
Chapter 2: Publishers & Subscribers .................................. 37
Section II: Operators ......................................................... 70
Chapter 3: Transforming Operators ................................... 72
Chapter 4: Filtering Operators ............................................. 92
Chapter 5: Combining Operators ...................................... 115
Chapter 6: Time Manipulation Operators ..................... 141
Chapter 7: Sequence Operators ........................................ 168
Chapter 8: In Practice: Project "Collage"........................ 190
Section III: Combine in Action ..................................... 214
Chapter 9: Networking .......................................................... 216
Chapter 10: Debugging ......................................................... 222
Chapter 11: Timers ................................................................. 227
Chapter 12: Key-Value Observing .................................... 232
Chapter 13: Resource Management ................................ 239
Chapter 14: In Practice: Project "News" ........................ 246

raywenderlich.com 3
Combine

Section IV: Advanced Combine ................................... 265


Chapter 15: In Practice: Combine & SwiftUI ................ 267
Chapter 16: Error Handling ................................................. 297
Chapter 17: Schedulers ......................................................... 324
Chapter 18: Custom Publishers & Handling
Backpressure ............................................................................. 348
Chapter 19: Testing ................................................................. 384
Section V: Building a Complete App .......................... 406
Chapter 20: In Practice: Building a Complete App ..... 407
Conclusion .............................................................................................. 438

raywenderlich.com 4
Combine

Table of Contents: Extended


About the Cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
About the Artist. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
What You Need . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Book License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Book Source Code & Forums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Section I: Introduction to Combine . . . . . . . . . . . . . . . . 20
Chapter 1: Hello, Combine! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Asynchronous programming. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Foundation of Combine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Combine basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
What's the benefit of Combine code over "standard" code? . . . . . . . . . 32
App architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Book projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Where to go from here?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Chapter 2: Publishers & Subscribers. . . . . . . . . . . . . . . . . . . . . . . . . 37
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Hello Publisher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Hello Subscriber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Hello Cancellable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Understanding what’s going on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Creating a custom subscriber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Hello Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Hello Subject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Dynamically adjusting demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Type erasure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

raywenderlich.com 5
Combine

Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Where to go from here?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

Section II: Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70


Chapter 3: Transforming Operators . . . . . . . . . . . . . . . . . . . . . . . . . 72
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Collecting values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Mapping values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Flattening publishers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Replacing upstream output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Incrementally transforming output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Where to go from here?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Chapter 4: Filtering Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Filtering basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Compacting and ignoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Finding values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Dropping values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Limiting values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Chapter 5: Combining Operators . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Prepending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Appending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Advanced combining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139

raywenderlich.com 6
Combine

Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140


Chapter 6: Time Manipulation Operators . . . . . . . . . . . . . . . . . . 141
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Shifting time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Collecting values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Collecting values (part 2) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Holding off on events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Timing out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Measuring time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Chapter 7: Sequence Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Finding values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Querying the publisher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Chapter 8: In Practice: Project "Collage" . . . . . . . . . . . . . . . . . . . 190
Getting started with "Collage" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Talking to other view controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Wrapping a callback function as a future . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Presenting a view controller as a future. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Sharing subscriptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Publishing properties with @Published . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Operators in practice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213

Section III: Combine in Action . . . . . . . . . . . . . . . . . . . . 214

raywenderlich.com 7
Combine

Chapter 9: Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216


URLSession extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Codable support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Publishing network data to multiple subscribers . . . . . . . . . . . . . . . . . . . 218
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Chapter 10: Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Printing events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
Acting on events — performing side effects . . . . . . . . . . . . . . . . . . . . . . . . . 224
Using the debugger as a last resort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Chapter 11: Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Using RunLoop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
Using the Timer class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
Using DispatchQueue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Chapter 12: Key-Value Observing . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Introducing publisher(for:options:) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Preparing and subscribing to your own KVO-compliant properties 233
ObservableObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
Chapter 13: Resource Management . . . . . . . . . . . . . . . . . . . . . . . 239
The share() operator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
The multicast(_:) operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245

raywenderlich.com 8
Combine

Chapter 14: In Practice: Project "News" . . . . . . . . . . . . . . . . . . . 246


Getting started with the Hacker News API . . . . . . . . . . . . . . . . . . . . . . . . . 247
Getting a single story . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
Multiple stories via merging publishers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Getting the latest stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

Section IV: Advanced Combine . . . . . . . . . . . . . . . . . . . 265


Chapter 15: In Practice: Combine & SwiftUI . . . . . . . . . . . . . . . 267
Hello, SwiftUI! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Getting started with "News" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
A first taste of managing view state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Fetching the latest stories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Using ObservableObject for model types . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Displaying errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Subscribing to an external publisher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Initializing the app's settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Editing the keywords list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
Chapter 16: Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Never . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Dealing with failure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
Chapter 17: Schedulers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
An introduction to schedulers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324

raywenderlich.com 9
Combine

Operators for scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326


Scheduler implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347
Chapter 18: Custom Publishers & Handling Backpressure 348
Creating your own publishers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
Publishers as extension methods. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349
The subscription mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
Publishers emitting values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352
Publishers transforming values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Handling backpressure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Chapter 19: Testing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Testing Combine operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
Testing production code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Challenges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405

Section V: Building a Complete App . . . . . . . . . . . . . . 406


Chapter 20: In Practice: Building a Complete App . . . . . . . . . 407
Getting started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
Setting goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
Implementing JokesViewModel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
Wiring JokesViewModel up to the UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Implementing Core Data with Combine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436

raywenderlich.com 10
Combine

Where to go from here? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437


Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438

raywenderlich.com 11
A About the Cover

The polar bear, although majestic on land, is also a passionate creature of the sea; its
scientific name, Ursus maritimus, means "sea bear"! Most polar bears spend the
majority of their lives on the edge of sea ice, waiting for a seal to swim by and make a
tasty lunch for the polar bear; for this reason, they are considered a marine mammal,
in the same vein as sea otters, manatees, and whales.

The sight of a polar bear cub instantly evokes that cute squeee feeling in all of us, but
make no mistake — these cuddly little cubs will soon grow into stealthy, patient, and
powerful adult hunters. The Combine framework, as well, is still in its infancy, and
even though there are other powerful competing frameworks like RxSwift, we think
that as Combine grows up, it will soon turn out to be as powerful, efficient and
stealthy as a polar bear — just not quite as cute!

raywenderlich.com 12
Combine About the Cover

Dedications
"To Jenn, for being so supportive and encouraging. To
Charlotte, keep up the great work in school — you motivate
me! To Betty, my best l’il friend for all her 18 years."

— Scott Gardner

"For my wife Elia and Baby Ethan—my love, inspiration, and


rock . To my family and friends for their support: Dad,
Mom, Ziv, Adam, and everyone else, you’re the best!"

— Shai Mishali

"To Fabienne and Alexandra ."

— Florent Pillet

"To my father. To my mom. To Mirjam and our beautiful


daughter."

— Marin Todorov

raywenderlich.com 13
Combine About the Cover

About the Authors


Scott Gardner is an author and the technical editor for this book.
He’s also authored over a dozen books, video courses, tutorials, and
articles on Swift and iOS app development — with a focus on
reactive programming. He’s an iOS Architect at Wayfair, and an
Apple Certified Trainer for Swift and iOS. You can find Scott on
Twitter or GitHub as @scotteg, or connect with him on LinkedIn at
scotteg.com.

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, 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.

Florent Pillet is an author of this book. He 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,
using it in production since 2015. A freelance developer, Florent
also uses reactive programming on the server side as well as on
Android and likes working on tools for developers like the popular
NSLogger when he's not contracting, training or reviewing code for
clients worldwide. Say hello to Florent on Twitter and GitHub at
@fpillet.

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. He's an independent contractor and
has worked for clients like Roche, Realm, and others. 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.

raywenderlich.com 14
Combine About the Cover

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 15
W What You Need

To follow along with this book, you’ll need the following:

• A Mac running macOS Mojave (10.14) or later. Earlier versions might work, but
they're untested.

• Xcode 11 or later. Xcode is the main development tool for iOS. You’ll need Xcode
11 or later for the tasks in this book, since Combine was introduced with the iOS 13
SDK. You can download the latest version of Xcode from Apple’s developer site
here: apple.co/2asi58y

• An intermediate level knowledge of Swift. This book teaches you how to write
declarative and reactive iOS applications using Apple's Combine framework.
Combine uses a multitude of advanced Swift features such as generics, so you
should have at least an intermediate-level knowledge of Swift.

If you want to try things out on a physical iOS device, you’ll need a developer
account with Apple, which you can obtain for free. However, all the sample projects
in this book will work just fine in the iOS Simulator bundled with Xcode, so a paid
developer account is completely optional.

raywenderlich.com 16
L Book License

By purchasing Combine: Asynchronous Programming with Swift, you have the


following license:

• You are allowed to use and/or modify the source code in Combine: Asynchronous
Programming with Swift in as many apps as you want, with no attribution required.

• You are allowed to use and/or modify all art, images and designs that are included
in Combine: Asynchronous Programming with Swift in as many apps as you want, but
must include this attribution line somewhere inside your app: “Artwork/images/
designs: from Combine: Asynchronous Programming with Swift, available at
www.raywenderlich.com”.

• The source code included in Combine: Asynchronous Programming with Swift is for
your personal use only. You are NOT allowed to distribute or sell the source code in
Combine: Asynchronous Programming with Swift without prior authorization.

• This book is for your personal use only. You are NOT allowed to sell this book
without prior authorization, or distribute it to friends, coworkers or students; they
would need to purchase their own copies.

All materials provided with this book are provided on an “as is” basis, without
warranty of any kind, express or 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 an action or contract, tort or otherwise, arising from, out of or in
connection with the software or the use or other dealings in the software.

All trademarks and registered trademarks appearing in this guide are the properties
of their respective owners.

raywenderlich.com 17
B Book Source Code &
Forums

If you bought the digital edition


This book comes with the source code for the starter and completed projects for each
chapter. These resources are shipped with the digital edition you downloaded here:

• https://store.raywenderlich.com/products/combine-asynchronous-programming-
with-swift.

If you bought the print version


You can get the source code for the print edition of the book here: https://
store.raywenderlich.com/products/combine-asynchronous-programming-with-
swift-source-code.

And if you purchased the print version of this book, you’re eligible to upgrade to the
digital editions at a significant discount! Simply email [email protected] with
your receipt for the physical copy and we’ll get you set up with the discounted digital
edition version of the book.

Forums
We’ve also set up an official forum for the book here:

• https://forums.raywenderlich.com.

This is a great place to ask questions about the book or to submit any errors you may
find.

raywenderlich.com 18
Combine Book Source Code & Forums

Digital book editions


We have a digital edition of this book available in both ePUB and PDF, which can be
handy if you want a soft copy to take with you, or you want to quickly search for a
specific term within the book.

Buying the digital edition version of the book also has a few extra benefits: free
updates each time we update the book, access to older versions of the book, and you
can download the digital editions from anywhere, at anytime.

Visit our book store page here:

• https://store.raywenderlich.com/products/combine-asynchronous-programming-
with-swift.

raywenderlich.com 19
Section I: Introduction to
Combine

In this part of the book, you're going to ramp up over the basics of Combine and
learn about some of the building blocks it comprises. You'll learn what Combine aims
to solve and what are some of the abstractions it provides to help you solve them:
Publisher, Subscriber, Subscription, Subject and much more.

Specifically, you'll cover:

Chapter 1: Hello, Combine!: A gentle introduction to what kind of problems


Combine solves, a back story of the roots of reactive programming on Apple's
platforms, and a crash course into the basic moving pieces of the framework.

Chapter 2: Publishers & Subscribers: The essence of Combine is that publishers


send values to subscribers. In this chapter you’ll learn all about what that means and
how to work with publishers and subscribers, and how to manage the subscriptions
that are created between the two of them.

raywenderlich.com 20
1 Chapter 1: Hello,
Combine!
By Marin Todorov

This book aims to introduce you to the Combine framework and to writing
declarative and reactive apps with Swift for Apple platforms.

In Apple's own words: "The Combine framework provides a declarative approach for
how your app processes events. Rather than potentially implementing multiple delegate
callbacks or completion handler closures, you can create a single processing chain for a
given event source. Each part of the chain is a Combine operator that performs a distinct
action on the elements received from the previous step."

Although very accurate and to the point, this delightful definition might sound a
little too abstract at first. That's why, before delving into coding exercises and
working on projects in the following chapters, you'll take a little time to learn a bit
about the problems Combine solves and the tools it uses to do so.

Once you've built up the relevant vocabulary and some understanding of the
framework in general, you'll move on to covering the basics while coding.

Gradually, as you progress in the book, you'll learn about more advanced topics and
eventually work through several projects.

When you've covered everything else you will, in the last chapter, work on a complete
app built with Combine.

raywenderlich.com 21
Combine Chapter 1: Hello, Combine!

Asynchronous programming
In a simple, single-threaded language, a program executes sequentially line-by-line.
For example, in pseudocode:

begin
var name = "Tom"
print(name)
name += " Harding"
print(name)
end

Synchronous code is easy to understand and makes it especially easy to argue about
the state of your data. With a single thread of execution, you can always be sure what
the current state of your data is. In the example above, you know that the first print
will always print "Tom" and the second will always print "Tom Harding".

Now, imagine you wrote the program in a multi-threaded language that is running
an asynchronous event-driven UI framework, like an iOS app running on Swift and
UIKit.

Consider what could potentially happen:

--- Thread 1 ---


begin
var name = "Tom"
print(name)

--- Thread 2 ---


name = "Billy Bob"

--- Thread 1 ---


name += " Harding"
print(name)
end

Here, the code sets name's value to "Tom" and then adds "Harding" to it, just like
before. But because another thread could execute at the same time, it's possible that
some other part of your program could run between the two mutations of name and
set it to another value like "Billy Bob".

When the code is running concurrently on different cores, it's difficult to say which
part of the code is going to modify the shared state first.

raywenderlich.com 22
Combine Chapter 1: Hello, Combine!

The code running on "Thread 2" in the example above might be:

• executing at exactly the same time on a different CPU core as your original code.

• executing just before name += " Harding", so instead of the original value "Tom",
it gets "Billy Bob" instead.

What exactly happens when you run this code depends on the system load, and you
might see different results each time you run the program.

Managing mutable state in your app becomes a loaded task once you run
asynchronous concurrent code.

Foundation and UIKit/AppKit


Apple has been improving asynchronous programming for their platforms over the
years. They've created several mechanisms you can use, on different system levels, to
create and execute asynchronous code. You’ve probably used these in your projects
without giving them a second thought because they are so fundamental to writing
mobile apps.

You’ve probably used most of the following:

• NotificationCenter: Executes a piece of code any time an event of interest


happens, such as when the user changes the orientation of the device or when the
software keyboard shows or hides on the screen.

• The delegate pattern: Lets you define an object that acts on behalf of, or in
coordination with, another object. For example, in your app delegate, you define
what should happen when a new remote notification arrives, but you have no idea
when this piece of code will be executed or how many times it will execute.

• Grand Central Dispatch and Operations: Helps you abstract the execution of
pieces of work. You can use them to schedule code to be executed sequentially in a
serial queue or to run a multitude of tasks concurrently in different queues with
different priorities.

• Closures: Create detached pieces of code that you can pass around in your code, so
other objects can decide whether to execute it, how many times, and in what
context.

Since most typical code performs some work asynchronously, and all UI events are
inherently asynchronous, it’s impossible to make assumptions about which order the
entirety of your app code will be executed.

raywenderlich.com 23
Combine Chapter 1: Hello, Combine!

And yet, writing good asynchronous programs is possible. It's just more complex
than... well, we'd like it to be. Unfortunately, asynchronous code and resource
sharing can produce issues which are difficult to reproduce, track down and
ultimately fix.

Certainly, one of the causes for these issues is the fact that a solid, real-life app most
likely uses all the different kinds of asynchronous APIs, each with its own interface,
like so:

Combine aims to introduce a new language to the Swift ecosystem that helps you
bring more order into the chaos of the asynchronous programming world.

Apple has integrated Combine's API deep into the Foundation framework, so Timer,
NotificationCenter and core frameworks like Core Data already speak its
language. Luckily, Combine is also very easy to integrate into your own code.

Finally, last but definitely not least, Apple designed their amazing new UI framework,
SwiftUI, to integrate easily with Combine as well.

To give you an idea of how committed Apple is to reactive programming with


Combine, here's a simple diagram showing where Combine sits in the system
hierarchy:

raywenderlich.com 24
Combine Chapter 1: Hello, Combine!

Various system frameworks, from Foundation all the way up to SwiftUI, depend on
Combine and offer Combine integration as an alternative to their "traditional" APIs.

Since Combine is an Apple framework, it doesn't aim to take away the role of well-
tested, solid APIs like Timer or NotificationCenter. Those Foundation types are
still present and doing their part. Instead, Combine integrates with them and allows
all the types in your app that want to talk asynchronously to each other do so via a
new, universal language.

So if the idea of using the same asynchronous tools to connect all the parts of your
app, from the data model to the networking layer and the user interface, sounds
interesting — you're in the right place, keep reading!

Foundation of Combine
Declarative, reactive programming isn't a new concept. It's been around for quite a
while, but it's made a fairly noticeable comeback in the last decade.

The first "modern-day" reactive solution came in a big way in 2009 when a team at
Microsoft launched a library called Reactive Extensions for .NET (Rx.NET).

Microsoft made that Rx.NET implementation open source in 2012, and since then,
many different languages have started to use its concepts. Currently, there are many
ports of the Rx standard like RxJS, RxKotlin, RxScala, RxPHP and more.

raywenderlich.com 25
Combine Chapter 1: Hello, Combine!

For Apple's platforms, there have been several third-party reactive frameworks like
RxSwift, which implements the Rx standard; ReactiveSwift, which was inspired by
Rx; Interstellar, which is a custom implementation and others.

Combine implements a standard that is different but similar to Rx, called Reactive
Streams. Reactive Streams has a few key differences from Rx, but they both agree on
most of the core concepts.

If you haven't previously used one or another of the frameworks mentioned above —
don't worry. So far, reactive programming has been a rather niche concept for Apple's
platforms, and especially with Swift.

In iOS 13/macOS Catalina, however, Apple brought reactive programming support to


its ecosystem via the built-in system framework, Combine.

As with any new technology from Apple, its application is at first slightly limited:
You can use Combine only for apps that support iOS 13/macOS Catalina or later. But
as with any technology that Apple bets on, its support will quickly become
widespread and the demand for Combine skills will surge.

With that said, start by learning some of Combine's basics to see how it can help you
write safe and solid asynchronous code.

Combine basics
In broad strokes, the three key moving pieces in Combine are publishers, operators
and subscribers. There are, of course, more players in the team, but without those
three you can't achieve much.

You'll learn in detail about publishers and subscribers in Chapter 2, “Publishers &
Subscribers,” and the complete second section of the book is devoted to acquainting
you with as many operators as humanly possible.

In this introductory chapter, however, you're going to get a simple crash course to
give you a general idea of the purpose those types have in the code and what their
responsibilities are.

raywenderlich.com 26
Combine Chapter 1: Hello, Combine!

Publishers
Publishers are types that can emit values over time to one or more interested parties,
such as subscribers. Regardless of the internal logic of the publisher, which can be
pretty much anything including math calculations, networking or handling user
events, every publisher can emit multiple events of these three types:

1. An output value of the publisher's generic Output type.

2. A successful completion.

3. A completion with an error of the publisher's Failure type.

A publisher can emit zero or more output values, and if it ever completes, either
successfully or due to a failure, it will not emit any other events.

Here's how a publisher emitting Int values could look like visualized on a timeline:

The blue boxes represent values that are emitted at a given time on the timeline, and
the numbers represent the emitted values. A vertical line, like the one you see on the
right-hand side of the diagram, represents a successful stream completion.

The simple contract of three possible events is so universal that it could represent
any kind of dynamic data in your program. That's why you can address any task in
your app using Combine publishers — regardless of whether it's about crunching
numbers, making network calls, reacting to user gestures or displaying data on-
screen.

raywenderlich.com 27
Combine Chapter 1: Hello, Combine!

Instead of always looking in your toolbox for the right tool to grab for the task at
hand, be it adding a delegate or injecting a completion callback — you can just use a
publisher instead.

One of the best features of publishers is that they come with error handling built in;
error handling isn't something you add optionally at the end, if you feel like it.

The Publisher protocol is generic over two types, as you might have noticed in the
diagram earlier:

• Publisher.Output is the type of the output values of the publisher. If the


publisher is specialized as an Int, it can never emit a String or a Date value.

• Publisher.Failure is the type of error the publisher can throw if it fails. If the
publisher can never fail, you specify that by using a Never failure type.

When you subscribe to a given publisher, you know what values to expect from it and
which errors it could fail with.

Operators
Operators are methods declared on the Publisher protocol that return either the
same or a new publisher. That's very useful because you can call a bunch of operators
one after the other, effectively chaining them together.

Because these methods, called "operators", are highly decoupled and composable,
they can be combined (aha!) to implement very complex logic over the execution of a
single subscription.

It's fascinating how operators fit tightly together like puzzle pieces. They cannot be
mistakenly put in the wrong order or fit together if one's output doesn't match the
next one's input type:

raywenderlich.com 28
Combine Chapter 1: Hello, Combine!

In a clear deterministic way, you can define the order of each of those asynchronous
abstracted pieces of work alongside with the correct input/output types and built-in
error handling. It's almost too good to be true!

As an added bonus, operators always have input and output, commonly referred to as
upstream and downstream — this allows them to avoid shared state (one of the
core issues we discussed earlier).

Operators focus on working with the data they receive from the previous operator
and provide their output to the next one in the chain. This means that no other
asynchronously-running piece of code can "jump in" and change the data you're
working on.

Subscribers
Finally, you arrive at the end of the subscription chain: Every subscription ends with
a subscriber. Subscribers generally do "something" with the emitted output or
completion events.

Currently, Combine provides two built-in subscribers, which make working with data
streams straightforward:

• The sink subscriber allows you to provide closures with your code that will receive
output values and completions. From there, you can do anything your heart desires
with the received events.

raywenderlich.com 29
Combine Chapter 1: Hello, Combine!

• The assign subscriber allows you to, without the need of custom code, bind the
resulting output to some property on your data model or on a UI control to display
the data directly on-screen via a key path.

Should you have other needs for your data, creating custom subscribers is even easier
than creating publishers. Combine uses a set of very simple protocols that allow you
to be able to build your own custom tools whenever the workshop doesn't offer the
right one for your task.

Subscriptions

Note: This book uses the term subscription to describe both Combine’s
Subscription protocol and its conforming objects, as well as the complete
chain of a publisher, operators and a subscriber.

When you add a subscriber at the end of a subscription, it "activates" the publisher all
the way at the beginning of the chain. This is a curious but important detail to
remember — publishers do not emit any values if there are no subscribers to
potentially receive the output.

Subscriptions are a wonderful concept in that they allow you to declare a chain of
asynchronous events with their own custom code and error handling only once, and
then you never have to think about it again.

If you go full-Combine, you could describe your whole app's logic via subscriptions
and once done, just let the system run everything without the need to push or pull
data or call back this or that other object:

raywenderlich.com 30
Combine Chapter 1: Hello, Combine!

Once the subscription code compiles successfully and there are no logic issues in
your custom code — you're done! The subscriptions, as designed, will asynchronously
"fire" each time some event like a user gesture, a timer going off or something else
awakes one of your publishers.

Even better, you don't need to specifically memory manage a subscription, thanks to
a protocol provided by Combine called Cancellable.

Both system-provided subscribers conform to Cancellable, which means that your


subscription code (e.g. the whole publisher, operators and subscriber call chain)
returns a Cancellable object. Whenever you release that object from memory, it
cancels the whole subscription and releases its resources from memory.

This means you can easily "bind" the lifespan of a subscription by storing it in a
property on your view controller, for example. This way, any time the user dismisses
the view controller from the view stack, that will deinitialize its properties and will
also cancel your subscription.

Or to automate this process, you can just have an [AnyCancellable] collection


property on your type and throw as many subscriptions inside it as you want. They'll
all be automatically canceled and released when the property is released from
memory.

As you see, there's plenty to learn, but it's all logical when explained in detail. And
that's exactly what the plan is for the next chapters — to bring you slowly but
steadily from zero to Combine hero by the end of this book.

raywenderlich.com 31
Combine Chapter 1: Hello, Combine!

What's the benefit of Combine code over


"standard" code?
You can, by all means, never use Combine and still create the best apps out there.
There's no argument about that. You can also create the best apps without Core Data,
URLSession, or even UIKit. But using those frameworks is more convenient, safe and
efficient than building those abstractions yourself.

Combine (and other system frameworks) aims to add another abstraction in your
async code. Another level of abstraction on the system level means tighter
integration that's well tested and a safe-bet technology for long-lasting support.

It's up to you to decide whether Combine is a great fit for your project or not, but
here are just a few "pro" reasons you might not have considered yet:

• Combine is integrated on the system level. That means Combine itself uses
language features that are not publicly available, offering you APIs that you
couldn't build yourself.

• The "old" style async code via delegates, IBAction or closures pushes you towards
writing custom code for each case of a button or a gesture you need to handle.
That's a lot of custom code to write tests for. Combine abstracts all async
operations in your code as "operators", which are already well tested.

• When all of your asynchronous pieces of work use the same interface — Publisher
— composition and reusability become extremely powerful.

• Combine's operators are highly composable. If you need to create a new one, that
new operator will instantly plug-and-play with the rest of Combine.

• Testing asynchronous code is usually more complex than testing synchronous


code. With Combine, however, the asynchronous operators are already tested, and
all that's left for you to do is test your business logic — that is, provide some input
and test if your subscription outputs the expected result.

As you see, most of the benefits revolve around safety and convenience. Combined
with the fact that the framework comes from Apple, investing in writing Combine
code looks promising.

raywenderlich.com 32
Combine Chapter 1: Hello, Combine!

App architecture
As this question is most likely already sounding alarms in your head, take a look at
how using Combine will change your pre-existing code and app architecture.

Combine is not a framework that affects how you structure your apps. Combine deals
with asynchronous data events and unified communication contract — it does not
alter, for example, how you would separate responsibilities in your project.

You can use Combine in your MVC (Model-View-Controller) apps, you can use it in
your MVVM (Model-View-ViewModel) code, in VIPER and so forth and so on.

This is one of the key aspects of adopting Combine that is important to understand
early — you can add Combine code iteratively and selectively, using it only in the
parts you wish to improve in your codebase. It's not an "all or nothing" choice you
need to make.

You could start by converting your data models, or adapting your networking layer, or
simply using Combine only in new code that you add to your app while keeping your
existing functionality as-is.

It's a slightly different story if you're adopting Combine and SwiftUI at the same
time. In that case, it really does make sense to drop the C from an MVC architecture.
But that's thanks to using Combine and SwiftUI in tandem — those two are simply on
fire when in the same room.

View controllers just don't have any chance against a Combine/SwiftUI team. When
you use reactive programming all the way from your data model to your views, you
don't need to have a special controller just to control your views:

raywenderlich.com 33
Combine Chapter 1: Hello, Combine!

If that sounds interesting, you're in for a treat, as this book includes a solid
introduction to using the two frameworks together in Chapter 15, “In Practice:
SwiftUI & Combine.”

Book projects
In this book, you'll start with the concepts first and move on to learning and trying
out a multitude of operators.

Unlike other system frameworks, you can work pretty successfully with Combine in
the isolated context of a playground.

Learning in an Xcode playground makes it easy to move forward and quickly


experiment as you progress through a given chapter and to see instantly the results
in Xcode's Console:

Combine does not require any third-party dependencies, so usually, a few simple
helper files included with the starter playground code for each chapter will suffice to
get you running. If Xcode ever gets stuck while you experiment in the playground, a
quick restart will likely solve the issue.

raywenderlich.com 34
Combine Chapter 1: Hello, Combine!

Once you move to more complex concepts than playing with a single operator, you'll
alternate between working in playgrounds and real Xcode projects like the Hacker
News app, which is a newsreader that displays news in real time:

It's important that, for each chapter, you begin with the provided starter playground
or project, as they might include some custom helper code which isn't relevant to
learning Combine. These tidbits are pre-written so you don't distract yourself from
the focus of that chapter.

In the last chapter, you’ll make use of all the skills you learned throughout the book
as you finish developing a complete iOS app that relies heavily on Combine and Core
Data. This will give you a final push on your road to building real-life applications
with Combine!

raywenderlich.com 35
Combine Chapter 1: Hello, Combine!

Key points
• Combine is a declarative, reactive framework for processing asynchronous events
over time.

• It aims to solve existing problems, like unifying tools for asynchronous


programming, dealing with mutable state and making error handling a starting
team player.

• Combine revolves around three main types: publishers to emit events over time,
operators to asynchronously process and manipulate upstream events and
subscribers to consume the results and do something useful with them.

Where to go from here?


Hopefully, this introductory chapter has been useful and has given you an initial
understanding of the issues Combine addresses as well as a look at some of the tools
it offers to make your asynchronous code safer and more reliable.

Another important takeaway from this chapter is what to expect from Combine and
what is out of its scope. Now, you know what you're in for when we speak of reactive
code or asynchronous events over time. And, of course, you don't expect using
Combine to magically solve your app's problems with navigation or drawing on-
screen.

Finally, having a taste of what's in store for you in the upcoming chapters has
hopefully gotten you excited about Combine and reactive programming with Swift.
Upwards and onwards, here we go!

raywenderlich.com 36
2 Chapter 2: Publishers &
Subscribers
By Scott Gardner

Now that you’ve learned some of the basic concepts of Combine, it’s time to jump in
and play with two of Combine’s core components — publishers and subscribers.

In this chapter, you’ll review several examples of creating publishers and subscribing
to those publishers using subscribers. By doing so, you’ll acquire important skills
that you’ll use throughout the rest of this book and beyond.

Getting started
Note: There are starter and final versions of the playgrounds and projects
you’ll use in each chapter throughout the book. The starter will be prepared
and ready for you to enter the code specified for each example and challenge.
You can compare your work with the final version at the end or along the way
if you get stuck.

raywenderlich.com 37
Combine Chapter 2: Publishers & Subscribers

For this chapter, you’ll use an Xcode playground with Combine imported. Open
Starter.playground in the projects folder and you’ll see the following:

Open Sources in the Project navigator (View ▸ Navigators ▸ Show Project


Navigator and twist down the Combine playground page), and select
SupportCode.swift. It contains the following helper function example(of:):

public func example(of description: String,


action: () -> Void) {
print("\n——— Example of:", description, "———")
action()
}

You’ll use this function to encapsulate some examples you’ll use throughout this
book.

However, before you begin playing with those examples, you first need to learn about
publishers, subscribers and subscriptions. They form the foundation of Combine and
enable you to send and receive data, typically asynchronously.

Hello Publisher
At the heart of Combine is the Publisher protocol. This protocol defines the
requirements for a type to be able to transmit a sequence of values over time to one
or more subscribers. In other words, a publisher publishes or emits events that can
include values of interest.

If you’ve developed on Apple platforms before, you can think of a publisher as kind of
like NotificationCenter. In fact, NotificationCenter now has a method named
publisher(for:object:) that provides a Publisher type that can publish
broadcasted notifications.

raywenderlich.com 38
Combine Chapter 2: Publishers & Subscribers

To check this out, go back to the starter playground and replace the Add your code
here placeholder with the following code:

example(of: "Publisher") {
// 1
let myNotification = Notification.Name("MyNotification")

// 2
let publisher = NotificationCenter.default
.publisher(for: myNotification, object: nil)
}

In this code, you:

1. Create a notification name.

2. Access NotificationCenter’s default center, call its publisher(for:object:)


method and assign its return value to a local constant.

Option-click on publisher(for:object:), and you’ll see that it returns a


Publisher that emits an event when the default notification center broadcasts a
notification.

So what’s the point of publishing notifications when a notification center is already


capable of broadcasting its notifications without a publisher? Glad you asked!

You can think of these types of methods as a bridge from the old to the new — a way
to Combine-ify existing APIs such as NotificationCenter.

A publisher emits two kinds of events:

1. Values, also referred to as elements.

2. A completion event.

A publisher can emit zero or more values but only one completion event, which can
either be a normal completion event or an error. Once a publisher emits a completion
event, it’s finished and can no longer emit any more events.

Before diving deeper into publishers and subscribers, you’ll first finish the example
of using traditional NotificationCenter APIs to receive a notification by
registering an observer. You’ll also unregister that observer when you’re no longer
interested in receiving that notification.

raywenderlich.com 39
Combine Chapter 2: Publishers & Subscribers

Add the following code to the end of the previous example:

// 3
let center = NotificationCenter.default

// 4
let observer = center.addObserver(
forName: myNotification,
object: nil,
queue: nil) { notification in
print("Notification received!")
}

// 5
center.post(name: myNotification, object: nil)

// 6
center.removeObserver(observer)

With this code, you:

3. Get a handle to the default notification center.

4. Create an observer to listen for the notification with the name you previously
created.

5. Post a notification with that name.

6. Remove the observer from the notification center.

Run the playground. You’ll see this output printed to the console:

——— Example of: Publisher ———


Notification received!

The example's title is a little misleading because the output is not actually coming
from a publisher. For that to happen, you need a subscriber.

Hello Subscriber
Subscriber is a protocol that defines the requirements for a type to be able to
receive input from a publisher. You’ll dive deeper into conforming to the Publisher
and Subscriber protocols shortly; for now, you’ll focus on the basic flow.

raywenderlich.com 40
Combine Chapter 2: Publishers & Subscribers

Add a new example to the playground that begins like the previous one:

example(of: "Subscriber") {
let myNotification = Notification.Name("MyNotification")

let publisher = NotificationCenter.default


.publisher(for: myNotification, object: nil)

let center = NotificationCenter.default


}

If you were to post a notification now, the publisher wouldn’t emit it — and that’s an
important distinction to remember. A publisher only emits an event when there’s at
least one subscriber.

Subscribing with sink(_:_:)


Continue in the previous example and add the following code to it:

// 1
let subscription = publisher
.sink { _ in
print("Notification received from a publisher!")
}

// 2
center.post(name: myNotification, object: nil)
// 3
subscription.cancel()

With this code, you:

1. Create a subscription by calling sink on the publisher.

2. Post the notification.

3. Cancel the subscription.

Don’t let the obscurity of the sink method name give you a sinking feeling. Option-
click on sink and you’ll see that it simply provides an easy way to attach a
subscriber with closures to handle output from a publisher. In this example, you
ignore those closures and instead just print a message to indicate that a notification
was received. You’ll learn more about canceling a subscription shortly.

Run the playground and you’ll see the following:

——— Example of: Publisher ———

raywenderlich.com 41
Combine Chapter 2: Publishers & Subscribers

Notification received from a publisher!

The sink operator will continue to receive as many values as the publisher emits.
This is known as unlimited demand, which you’ll learn more about shortly. And
although you ignored them in the previous example, the sink operator actually
provides two closures: one to handle receiving a completion event, and one to handle
receiving values.

raywenderlich.com 42
Combine Chapter 2: Publishers & Subscribers

To see how this works, add this new example to your playground:

example(of: "Just") {
// 1
let just = Just("Hello world!")

// 2
_ = just
.sink(
receiveCompletion: {
print("Received completion", $0)
},
receiveValue: {
print("Received value", $0)
})
}

Here, you:

1. Create a publisher using Just, which lets you create a publisher from a primitive
value type.

2. Create a subscription to the publisher and print a message for each received
event.

Run the playground. You’ll see the following:

——— Example of: Just ———


Received value Hello world!
Received completion finished

Option-click on Just and the Quick Help explains that it’s a publisher that emits its
output to each subscriber once and then finishes.

Try adding another subscriber by adding the following code to the end of your
example:

_ = just
.sink(
receiveCompletion: {
print("Received completion (another)", $0)
},
receiveValue: {
print("Received value (another)", $0)
})

Run the playground. True to its word, a Just happily emits its output to each new
subscriber exactly once and then finishes.

raywenderlich.com 43
Combine Chapter 2: Publishers & Subscribers

Received value (another) Hello world!


Received completion (another) finished

Subscribing with assign(to:on:)


In addition to sink, the built-in assign(to:on:) operator enables you to assign the
received value to a KVO-compliant property of an object.

Add this example to see how this works:

example(of: "assign(to:on:)") {
// 1
class SomeObject {
var value: String = "" {
didSet {
print(value)
}
}
}

// 2
let object = SomeObject()

// 3
let publisher = ["Hello", "world!"].publisher

// 4
_ = publisher
.assign(to: \.value, on: object)
}

From the top:

1. Define a class with a property that has a didSet property observer that prints the
new value.

2. Create an instance of that class.

3. Create a publisher from an array of strings.

4. Subscribe to the publisher, assigning each value received to the value property of
the object.

Run the playground and you will see printed:

——— Example of: assign(to:on:) ———


Hello
world!

raywenderlich.com 44
Combine Chapter 2: Publishers & Subscribers

You’ll focus on using the sink operator for now — but fear not, you’ll get more
hands-on practice using assign beginning in Chapter 8, “In Practice: Project
"Collage".”

Hello Cancellable
When a subscriber is done and no longer wants to receive values from a publisher,
it’s a good idea to cancel the subscription to free up resources and stop any
corresponding activities from occurring, such as network calls.

Subscriptions return an instance of AnyCancellable as a "cancellation token," which


makes it possible to cancel the subscription when you’re done with it.
AnyCancellable conforms to the Cancellable protocol, which requires the
cancel() method exactly for that purpose.

Finish the Subscriber example from earlier by adding the following code:

// 1
center.post(name: myNotification, object: nil)

// 2
subscription.cancel()

With this code, you:

1. Post a notification (same as before).

2. Cancel the subscription. You’re able to call cancel() on the subscription because
the Subscription protocol inherits from Cancellable.

Run the playground. You’ll see the following:

——— Example of: Subscriber ———


Notification received from a publisher!

If you don’t explicitly call cancel() on a subscription, it will continue until the
publisher completes, or until normal memory management causes a stored
subscription to be deinitialized. At that point it will cancel the subscription for you.

raywenderlich.com 45
Combine Chapter 2: Publishers & Subscribers

Note: It’s also fine to ignore the return value from a subscription in a
playground (for example, _ = just.sink...). However, one caveat: if you
don’t store a subscription in full projects, that subscription will cancel as soon
as the program flow exits the scope in which it was created!

These are good examples to start with, but there’s a lot more going on behind the
scenes. It’s time to lift the curtain and learn more about the roles of publishers,
subscribers and subscriptions in Combine.

Understanding what’s going on


They say a picture is worth a thousand words, so let’s kick things off with one to
explain the interplay between publishers and subscribers:

Walking through this UML diagram:

1. The subscriber subscribes to the publisher.

2. The publisher creates a subscription and gives it to the subscriber.

3. The subscriber requests values.

raywenderlich.com 46
Combine Chapter 2: Publishers & Subscribers

4. The publisher sends values.

5. The publisher sends a completion.

Note: The above diagram provides a streamlined overview of what’s going on.
What you’ll learn here is enough to get you started working with Combine.
You’ll gain a deeper understanding of this process in Chapter 18, “Custom
Publishers & Handling Backpressure.”

Take a look at the Publisher protocol and one of its most crucial extensions:

public protocol Publisher {


// 1
associatedtype Output

// 2
associatedtype Failure : Error

// 4
func receive<S>(subscriber: S)
where S: Subscriber,
Self.Failure == S.Failure,
Self.Output == S.Input
}

extension Publisher {
// 3
public func subscribe<S>(_ subscriber: S)
where S : Subscriber,
Self.Failure == S.Failure,
Self.Output == S.Input
}

Here’s a closer look:

1. The type of values that the publisher can produce.

2. The type of error a publisher may produce, or Never if the publisher is


guaranteed to not produce an error.

3. A subscriber calls subscribe(_:) on a publisher to attach to it.

4. The implementation of subscribe(_:) will call receive(subscriber:) to


attach the subscriber to the publisher, i.e., create a subscription.

The associated types are the publisher’s interface that a subscriber must match in
order to create a subscription.

raywenderlich.com 47
Combine Chapter 2: Publishers & Subscribers

Now, look at the Subscriber protocol:

public protocol Subscriber: CustomCombineIdentifierConvertible {


// 1
associatedtype Input

// 2
associatedtype Failure: Error

// 3
func receive(subscription: Subscription)

// 4
func receive(_ input: Self.Input) -> Subscribers.Demand

// 5
func receive(completion: Subscribers.Completion<Self.Failure>)
}

Here’s a closer look:

1. The type of values a subscriber can receive.

2. The type of error a subscriber can receive; or Never if the subscriber won’t
receive an error.

3. The publisher calls receive(subscription:) on the subscriber to give it the


subscription.

4. The publisher calls receive(_:) on the subscriber to send it a new value that it
just published.

5. The publisher calls receive(completion:) on the subscriber to tell it that it has


finished producing values, either normally or due to an error.

The connection between the publisher and the subscriber is the subscription. Here’s
the Subscription protocol:

public protocol Subscription: Cancellable,


CustomCombineIdentifierConvertible {
func request(_ demand: Subscribers.Demand)
}

The subscriber calls request(_:) to indicate it is willing to receive more values, up


to a max number or unlimited.

Note: The concept of a subscriber stating how many values it’s willing to

raywenderlich.com 48
Combine Chapter 2: Publishers & Subscribers

receive is known as backpressure management. Without it, or some other


strategy, a subscriber could get flooded with more values from the publisher
than it can handle, and this can lead to problems. Backpressure is also covered
in depth in Chapter 18, “Custom Publishers & Handling Backpressure.”

In Subscriber, notice that receive(_:) returns a Demand. Even though the max
number of values a subscriber is willing to receive is specified when initially calling
subscription.request(_:) in receive(_:), you can adjust that max each time a
new value is received.

Note: Adjusting max in Subscriber.receive(_:) is additive, i.e., the new max


value is added to the current max. The max value must be positive, and passing
a negative value will result in a fatalError. This means that you can increase
the original max each time a new value is received, but you cannot decrease it.

Creating a custom subscriber


Time to put what you just learned to practice. Add this new example to your
playground:

example(of: "Custom Subscriber") {


// 1
let publisher = (1...6).publisher

// 2
final class IntSubscriber: Subscriber {
// 3
typealias Input = Int
typealias Failure = Never

// 4
func receive(subscription: Subscription) {
subscription.request(.max(3))
}

// 5
func receive(_ input: Int) -> Subscribers.Demand {
print("Received value", input)
return .none
}

// 6

raywenderlich.com 49
Combine Chapter 2: Publishers & Subscribers

func receive(completion: Subscribers.Completion<Never>) {


print("Received completion", completion)
}
}
}

What you do here is:

1. Create a publisher of integers via the range’s publisher property.

2. Define a custom subscriber, IntSubscriber.

3. Implement the type aliases to specify that this subscriber can receive integer
inputs and will never receive errors.

4. Implement the required methods, beginning with receive(subscription:),


which is called by the publisher; and in that method, call .request(_:) on the
subscription specifying that the subscriber is willing to receive up to three values
upon subscription.

5. Print each value as it’s received and return .none, indicating that the subscriber
will not adjust its demand; .none is equivalent to .max(0).

6. Print the completion event.

For the publisher to publish anything, it needs a subscriber. Add the following at the
end of the example:

let subscriber = IntSubscriber()

publisher.subscribe(subscriber)

In this code, you create a subscriber that matches the Output and Failure types of
the publisher. You then tell the publisher to subscribe, or attach, the subscriber.

Run the playground. You’ll see the following printed to the console:

——— Example of: Custom Subscriber ———


Received value 1
Received value 2
Received value 3

You did not receive a completion event. This is because the publisher has a finite
number of values, and you specified a demand of .max(3).

In your custom subscriber’s receive(_:), try changing .none to .unlimited, so


your receive(_:) method looks like this:

raywenderlich.com 50
Another Random Scribd Document
with Unrelated Content
FINIS

JARROLD AND SONS, PRINTERS, NORWICH.

Transcriber’s Notes:
Archaic and inconsistent punctuation and
spelling retained.
Inconsistent question formats were
regularized.
*** END OF THE PROJECT GUTENBERG EBOOK A GUIDE TO THE
SCIENTIFIC KNOWLEDGE OF THINGS FAMILIAR ***

Updated editions will replace the previous one—the old editions


will be renamed.

Creating the works from print editions not protected by U.S.


copyright law means that no one owns a United States
copyright in these works, so the Foundation (and you!) can copy
and distribute it in the United States without permission and
without paying copyright royalties. Special rules, set forth in the
General Terms of Use part of this license, apply to copying and
distributing Project Gutenberg™ electronic works to protect the
PROJECT GUTENBERG™ concept and trademark. Project
Gutenberg is a registered trademark, and may not be used if
you charge for an eBook, except by following the terms of the
trademark license, including paying royalties for use of the
Project Gutenberg trademark. If you do not charge anything for
copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such
as creation of derivative works, reports, performances and
research. Project Gutenberg eBooks may be modified and
printed and given away—you may do practically ANYTHING in
the United States with eBooks not protected by U.S. copyright
law. Redistribution is subject to the trademark license, especially
commercial redistribution.

START: FULL LICENSE


THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK

To protect the Project Gutenberg™ mission of promoting the


free distribution of electronic works, by using or distributing this
work (or any other work associated in any way with the phrase
“Project Gutenberg”), you agree to comply with all the terms of
the Full Project Gutenberg™ License available with this file or
online at www.gutenberg.org/license.

Section 1. General Terms of Use and


Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand,
agree to and accept all the terms of this license and intellectual
property (trademark/copyright) agreement. If you do not agree
to abide by all the terms of this agreement, you must cease
using and return or destroy all copies of Project Gutenberg™
electronic works in your possession. If you paid a fee for
obtaining a copy of or access to a Project Gutenberg™
electronic work and you do not agree to be bound by the terms
of this agreement, you may obtain a refund from the person or
entity to whom you paid the fee as set forth in paragraph 1.E.8.

1.B. “Project Gutenberg” is a registered trademark. It may only


be used on or associated in any way with an electronic work by
people who agree to be bound by the terms of this agreement.
There are a few things that you can do with most Project
Gutenberg™ electronic works even without complying with the
full terms of this agreement. See paragraph 1.C below. There
are a lot of things you can do with Project Gutenberg™
electronic works if you follow the terms of this agreement and
help preserve free future access to Project Gutenberg™
electronic works. See paragraph 1.E below.
1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright
law in the United States and you are located in the United
States, we do not claim a right to prevent you from copying,
distributing, performing, displaying or creating derivative works
based on the work as long as all references to Project
Gutenberg are removed. Of course, we hope that you will
support the Project Gutenberg™ mission of promoting free
access to electronic works by freely sharing Project Gutenberg™
works in compliance with the terms of this agreement for
keeping the Project Gutenberg™ name associated with the
work. You can easily comply with the terms of this agreement
by keeping this work in the same format with its attached full
Project Gutenberg™ License when you share it without charge
with others.

1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside
the United States, check the laws of your country in addition to
the terms of this agreement before downloading, copying,
displaying, performing, distributing or creating derivative works
based on this work or any other Project Gutenberg™ work. The
Foundation makes no representations concerning the copyright
status of any work in any country other than the United States.

1.E. Unless you have removed all references to Project


Gutenberg:

1.E.1. The following sentence, with active links to, or other


immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project
Gutenberg™ work (any work on which the phrase “Project
Gutenberg” appears, or with which the phrase “Project
Gutenberg” is associated) is accessed, displayed, performed,
viewed, copied or distributed:

This eBook is for the use of anyone anywhere in the United


States and most other parts of the world at no cost and
with almost no restrictions whatsoever. You may copy it,
give it away or re-use it under the terms of the Project
Gutenberg License included with this eBook or online at
www.gutenberg.org. If you are not located in the United
States, you will have to check the laws of the country
where you are located before using this eBook.

1.E.2. If an individual Project Gutenberg™ electronic work is


derived from texts not protected by U.S. copyright law (does not
contain a notice indicating that it is posted with permission of
the copyright holder), the work can be copied and distributed to
anyone in the United States without paying any fees or charges.
If you are redistributing or providing access to a work with the
phrase “Project Gutenberg” associated with or appearing on the
work, you must comply either with the requirements of
paragraphs 1.E.1 through 1.E.7 or obtain permission for the use
of the work and the Project Gutenberg™ trademark as set forth
in paragraphs 1.E.8 or 1.E.9.

1.E.3. If an individual Project Gutenberg™ electronic work is


posted with the permission of the copyright holder, your use and
distribution must comply with both paragraphs 1.E.1 through
1.E.7 and any additional terms imposed by the copyright holder.
Additional terms will be linked to the Project Gutenberg™
License for all works posted with the permission of the copyright
holder found at the beginning of this work.

1.E.4. Do not unlink or detach or remove the full Project


Gutenberg™ License terms from this work, or any files
containing a part of this work or any other work associated with
Project Gutenberg™.

1.E.5. Do not copy, display, perform, distribute or redistribute


this electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the
Project Gutenberg™ License.

1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if
you provide access to or distribute copies of a Project
Gutenberg™ work in a format other than “Plain Vanilla ASCII” or
other format used in the official version posted on the official
Project Gutenberg™ website (www.gutenberg.org), you must,
at no additional cost, fee or expense to the user, provide a copy,
a means of exporting a copy, or a means of obtaining a copy
upon request, of the work in its original “Plain Vanilla ASCII” or
other form. Any alternate format must include the full Project
Gutenberg™ License as specified in paragraph 1.E.1.

1.E.7. Do not charge a fee for access to, viewing, displaying,


performing, copying or distributing any Project Gutenberg™
works unless you comply with paragraph 1.E.8 or 1.E.9.

1.E.8. You may charge a reasonable fee for copies of or


providing access to or distributing Project Gutenberg™
electronic works provided that:

• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”

• You provide a full refund of any money paid by a user who


notifies you in writing (or by e-mail) within 30 days of receipt
that s/he does not agree to the terms of the full Project
Gutenberg™ License. You must require such a user to return or
destroy all copies of the works possessed in a physical medium
and discontinue all use of and all access to other copies of
Project Gutenberg™ works.

• You provide, in accordance with paragraph 1.F.3, a full refund of


any money paid for a work or a replacement copy, if a defect in
the electronic work is discovered and reported to you within 90
days of receipt of the work.

• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.

1.E.9. If you wish to charge a fee or distribute a Project


Gutenberg™ electronic work or group of works on different
terms than are set forth in this agreement, you must obtain
permission in writing from the Project Gutenberg Literary
Archive Foundation, the manager of the Project Gutenberg™
trademark. Contact the Foundation as set forth in Section 3
below.

1.F.

1.F.1. Project Gutenberg volunteers and employees expend


considerable effort to identify, do copyright research on,
transcribe and proofread works not protected by U.S. copyright
law in creating the Project Gutenberg™ collection. Despite these
efforts, Project Gutenberg™ electronic works, and the medium
on which they may be stored, may contain “Defects,” such as,
but not limited to, incomplete, inaccurate or corrupt data,
transcription errors, a copyright or other intellectual property
infringement, a defective or damaged disk or other medium, a
computer virus, or computer codes that damage or cannot be
read by your equipment.

1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except


for the “Right of Replacement or Refund” described in
paragraph 1.F.3, the Project Gutenberg Literary Archive
Foundation, the owner of the Project Gutenberg™ trademark,
and any other party distributing a Project Gutenberg™ electronic
work under this agreement, disclaim all liability to you for
damages, costs and expenses, including legal fees. YOU AGREE
THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT
LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT
EXCEPT THOSE PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE
THAT THE FOUNDATION, THE TRADEMARK OWNER, AND ANY
DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE
TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL,
PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE
NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.

1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you


discover a defect in this electronic work within 90 days of
receiving it, you can receive a refund of the money (if any) you
paid for it by sending a written explanation to the person you
received the work from. If you received the work on a physical
medium, you must return the medium with your written
explanation. The person or entity that provided you with the
defective work may elect to provide a replacement copy in lieu
of a refund. If you received the work electronically, the person
or entity providing it to you may choose to give you a second
opportunity to receive the work electronically in lieu of a refund.
If the second copy is also defective, you may demand a refund
in writing without further opportunities to fix the problem.

1.F.4. Except for the limited right of replacement or refund set


forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’,
WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.

1.F.5. Some states do not allow disclaimers of certain implied


warranties or the exclusion or limitation of certain types of
damages. If any disclaimer or limitation set forth in this
agreement violates the law of the state applicable to this
agreement, the agreement shall be interpreted to make the
maximum disclaimer or limitation permitted by the applicable
state law. The invalidity or unenforceability of any provision of
this agreement shall not void the remaining provisions.

1.F.6. INDEMNITY - You agree to indemnify and hold the


Foundation, the trademark owner, any agent or employee of the
Foundation, anyone providing copies of Project Gutenberg™
electronic works in accordance with this agreement, and any
volunteers associated with the production, promotion and
distribution of Project Gutenberg™ electronic works, harmless
from all liability, costs and expenses, including legal fees, that
arise directly or indirectly from any of the following which you
do or cause to occur: (a) distribution of this or any Project
Gutenberg™ work, (b) alteration, modification, or additions or
deletions to any Project Gutenberg™ work, and (c) any Defect
you cause.

Section 2. Information about the Mission


of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new
computers. It exists because of the efforts of hundreds of
volunteers and donations from people in all walks of life.

Volunteers and financial support to provide volunteers with the


assistance they need are critical to reaching Project
Gutenberg™’s goals and ensuring that the Project Gutenberg™
collection will remain freely available for generations to come. In
2001, the Project Gutenberg Literary Archive Foundation was
created to provide a secure and permanent future for Project
Gutenberg™ and future generations. To learn more about the
Project Gutenberg Literary Archive Foundation and how your
efforts and donations can help, see Sections 3 and 4 and the
Foundation information page at www.gutenberg.org.

Section 3. Information about the Project


Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-
profit 501(c)(3) educational corporation organized under the
laws of the state of Mississippi and granted tax exempt status
by the Internal Revenue Service. The Foundation’s EIN or
federal tax identification number is 64-6221541. Contributions
to the Project Gutenberg Literary Archive Foundation are tax
deductible to the full extent permitted by U.S. federal laws and
your state’s laws.

The Foundation’s business office is located at 809 North 1500


West, Salt Lake City, UT 84116, (801) 596-1887. Email contact
links and up to date contact information can be found at the
Foundation’s website and official page at
www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission
of increasing the number of public domain and licensed works
that can be freely distributed in machine-readable form
accessible by the widest array of equipment including outdated
equipment. Many small donations ($1 to $5,000) are particularly
important to maintaining tax exempt status with the IRS.

The Foundation is committed to complying with the laws


regulating charities and charitable donations in all 50 states of
the United States. Compliance requirements are not uniform
and it takes a considerable effort, much paperwork and many
fees to meet and keep up with these requirements. We do not
solicit donations in locations where we have not received written
confirmation of compliance. To SEND DONATIONS or determine
the status of compliance for any particular state visit
www.gutenberg.org/donate.

While we cannot and do not solicit contributions from states


where we have not met the solicitation requirements, we know
of no prohibition against accepting unsolicited donations from
donors in such states who approach us with offers to donate.

International donations are gratefully accepted, but we cannot


make any statements concerning tax treatment of donations
received from outside the United States. U.S. laws alone swamp
our small staff.

Please check the Project Gutenberg web pages for current


donation methods and addresses. Donations are accepted in a
number of other ways including checks, online payments and
credit card donations. To donate, please visit:
www.gutenberg.org/donate.

Section 5. General Information About


Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could
be freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose
network of volunteer support.

Project Gutenberg™ eBooks are often created from several


printed editions, all of which are confirmed as not protected by
copyright in the U.S. unless a copyright notice is included. Thus,
we do not necessarily keep eBooks in compliance with any
particular paper edition.

Most people start at our website which has the main PG search
facility: www.gutenberg.org.

This website includes information about Project Gutenberg™,


including how to make donations to the Project Gutenberg
Literary Archive Foundation, how to help produce our new
eBooks, and how to subscribe to our email newsletter to hear
about new eBooks.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookbell.com

You might also like