Combine Asynchronous Programming With Swift First Edition Tutorial Team pdf download
Combine Asynchronous Programming With Swift First Edition Tutorial Team pdf download
https://ebookbell.com/product/combine-asynchronous-programming-
with-swift-first-edition-tutorial-team-38411528
https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-first-edition-scott-gardner-11711318
https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-2nd-edition-scott-gardner-36336544
https://ebookbell.com/product/combine-asynchronous-programming-with-
swift-third-edition-3rd-edition-scott-gardner-36336580
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
https://ebookbell.com/product/asynchronous-programming-with-swiftui-
and-combine-1st-peter-friese-47531966
https://ebookbell.com/product/combine-or-combust-cooperating-on-
chemicals-and-hazardous-substances-management-asiaeurope-
foundation-2428176
https://ebookbell.com/product/combine-harvesters-theory-modeling-and-
design-miu-petre-5264472
https://ebookbell.com/product/combine-mastery-in-swiftui-mark-
moeykens-54302816
Combine
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
raywenderlich.com 3
Combine
raywenderlich.com 4
Combine
raywenderlich.com 5
Combine
Challenge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Key points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Where to go from here?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
raywenderlich.com 6
Combine
raywenderlich.com 7
Combine
raywenderlich.com 8
Combine
raywenderlich.com 9
Combine
raywenderlich.com 10
Combine
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
— Shai Mishali
— Florent Pillet
— Marin Todorov
raywenderlich.com 13
Combine About the Cover
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.
raywenderlich.com 14
Combine About the Cover
raywenderlich.com 15
W What You Need
• 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
• 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
• https://store.raywenderlich.com/products/combine-asynchronous-programming-
with-swift.
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
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.
• 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.
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.
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.
• 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.
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.
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:
2. A successful completion.
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.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.
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.
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!
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.
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.
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.
• 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.
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:
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)
}
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.
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
// 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)
4. Create an observer to listen for the notification with the name you previously
created.
Run the playground. You’ll see this output printed to the console:
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")
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.
// 1
let subscription = publisher
.sink { _ in
print("Notification received from a publisher!")
}
// 2
center.post(name: myNotification, object: nil)
// 3
subscription.cancel()
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.
raywenderlich.com 41
Combine Chapter 2: Publishers & Subscribers
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.
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
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)
}
1. Define a class with a property that has a didSet property observer that prints the
new value.
4. Subscribe to the publisher, assigning each value received to the value property of
the object.
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.
Finish the Subscriber example from earlier by adding the following code:
// 1
center.post(name: myNotification, object: nil)
// 2
subscription.cancel()
2. Cancel the subscription. You’re able to call cancel() on the subscription because
the Subscription protocol inherits from Cancellable.
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.
raywenderlich.com 46
Combine Chapter 2: Publishers & Subscribers
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:
// 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
}
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
// 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>)
}
2. The type of error a subscriber can receive; or Never if the subscriber won’t
receive an error.
4. The publisher calls receive(_:) on the subscriber to send it a new value that it
just published.
The connection between the publisher and the subscriber is the subscription. Here’s
the Subscription protocol:
Note: The concept of a subscriber stating how many values it’s willing to
raywenderlich.com 48
Combine Chapter 2: Publishers & Subscribers
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.
// 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
3. Implement the type aliases to specify that this subscriber can receive integer
inputs and will never receive errors.
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).
For the publisher to publish anything, it needs a subscriber. Add the following at the
end of the example:
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:
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).
raywenderlich.com 50
Another Random Scribd Document
with Unrelated Content
FINIS
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 ***
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.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.
• 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 comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.F.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
ebookbell.com