WWDC2016 Session 218

Transcript

[ Music ]
[ Applause ]
>> Great.
Hello, and welcome
to our session
on keeping your Watch
App up to date.
My name is Eric Lanz, and
with me today is Austen Green.
We're both engineers
on the watchOS team.
Here you see a screenshot
from our calendar app.
When you hear the word app, this
is probably what comes to mind,
but watchOS has many ways
to interact beyond the
standard application.
For example, your users
think of your notifications
For example, your users
think of your notifications
as an important part
of your app.
If you have a complication,
your users think of that
as an important part
of your app, too.
In watchOS 3, we're introducing
the new application dock.
This feature allows
users to add up to ten
of their favorite applications
to an always accessible dock.
They can then swipe through
the dock to get a quick look
at their data in one place.
This is now also
part of your app.
People are using your
application's data
in many different ways and
expect all of those ways to be
in sync and up to
date all the time.
This may sound like
an impossible task,
but don't worry.
We're here to help.
Today we'll be talking
about five topics.
First, an overview of this API
and how it works on watchOS.
Next, a walkthrough
of an example application
with some real code.
Then Austen will come on stage
and show you how scheduling
works behind the scenes.
and show you how scheduling
works behind the scenes.
After that, we'll share
some best practices
for adopting this API in
your own applications.
To close out the session,
we'll go through a case study
of how we adopted this API in
our own stocks application.
Let's get started by thinking
about how we use our phones
and our watches in different
ways throughout the day.
In the morning, you can
start your day waiting
in line for coffee.
You can then browse the news on
your phone for a few minutes.
Before you leave the shop,
you check the weather
with the complication on your
watch face, a two-second task.
For lunch, you use maps again
to find a great restaurant.
After a few minutes,
you've made your choice
and put your phone away.
On the way to the restaurant,
you get a notification.
A quick glance at your wrist
lets you know your friends will
be a few minutes late,
another two-second task.
At the end of the day,
you use maps again
to plan your route,
maybe a detour.
You get an iMessage asking
when you'll be home that night.
You get an iMessage asking
when you'll be home that night.
Use the quick reply features
of watchOS 3 to send back,
"On my way," another
two-second task.
It simply is impossible to have
our data ready in the couple
of seconds that users
are going to give us.
We need more time,
and background refresh
is the way to get it.
This powerful new API allows
you to schedule runtime
so you can have your data
ready before the user needs it.
To understand what this new API
can do, let's take a closer look
at checking the weather
on watchOS.
Here we see the foreground
activity of looking
at the weather complication.
Our data would have to be
ready before this happened.
So let's use this API to
schedule some time in advance
to update our UI, but how can
we update our UI without data.
We'll need more time to
get the latest weather data
from our server.
So let's schedule
a task for that.
But how did we even get
started on this chain of events?
But how did we even get
started on this chain of events?
We're going to need
a way for the system
to wake our application
in the background.
On watchOS, the system
wakes your application
by giving it a task.
The system has a limited
number of these available.
So make the best use
of each one you get.
When the system wants to
wake your application,
it delivers one or more
of these task objects.
Make sure to hold
on to this task
until you're finished
processing your data.
The system delivers tasks
by calling the new handled
background task method
on WK extension delegate.
We'll go through an example
of this method later on today.
When you're finished with your
background work, return the task
to the system by completing it.
This is the fundamental process
by which you obtain
background runtime on watchOS.
Now that we understand the
task system from a high level,
let's dive in and look at
the specific types of tasks
that the system can
create for us.
First, this is the
application task.
This is a generic runtime
task that you can schedule
to have your application
woken at a future date.
Within the application
task runtime,
you can do any kind
of local processing.
You may want to update
your complication timeline
or download some data from
your server with URLSession.
The URLSession task
is how you find
out that your data has
finished downloading
and ready to process.
Since watchOS is a shared
ecosystem, it doesn't make sense
to leave our application running
while the data downloads.
It would be better to allow
our application to sleep,
and let the system
do that for us.
Snapshots are a very
important part of watchOS 3.
They are both your launch image
and your preview image
while running in the dock.
If the user settles on your app,
it will start running
live again.
So it's critical
that your snapshot be
up to date at all times.
The snapshot task is how you
get runtime to prepare your UI
The snapshot task is how you
get runtime to prepare your UI
in the background to be
ready for the new snapshot.
When you complete this task,
the system will automatically
snapshot your UI.
Remember to always
schedule one of these
after you finish
processing data,
or the user won't see
the work you just did.
When a notification arrives,
your user will see it.
They will then expect your
complication and your snapshot
to be updated to
reflect this data.
Users love applications that
feel like a consistent part
of the OS and are more likely
to put those apps in the dock.
If the user does not interact
with your application for more
than one hour, the system is
going to give you an opportunity
to restore your default state.
Default state means different
things to different apps,
and some apps have no
concept of a default state.
Designing great snapshots
is a huge
and important topic
on watchOS 3.
and important topic
on watchOS 3.
We recommend you check
out this other session
for some great advice
on designing excellent
snapshots for your users.
The last task type is
for watch connectivity.
On watchOS 3, we've
integrated watch connectivity
with our background refresh API.
This means you can now use
watch connectivity messaging
to get data to your
application while it is running
in the background.
Complication push, application
context, sending a file,
or sending user info will
all wake your application
in the background.
We hope that this
edition will lead
to even richer watch
experiences for our users.
When your application is woken
via watch connectivity tasks,
use the standard API
to get your data.
First, make sure the
session is active.
Once the session reactivates,
start monitoring the new
hasContentPending property.
As long as this property
is true,
As long as this property
is true,
you still have data to process.
Make sure to hold onto the task
until you're finished
processing this data.
It is your responsibility
to return the task
to the system by completing it.
If you don't do this, you will
exhaust your background runtime,
and we're going to give
you a crash report.
Austen will talk more in the
second half of this session
about these runtime caveats.
Let's quickly review
the workflow
of using our new
background refresh API.
First, schedule a task.
Next, receive the
task from the system.
Now you can do your
background work.
Make sure to hold onto the task
until you're finished
doing this work.
You may use this runtime
to schedule further work
such as fetching data from
your server with URLSession.
When finished, return the task
to the system by completing it.
Before we continue, I want
to stress an important
topic, being a good citizen.
to stress an important
topic, being a good citizen.
watchOS is a shared ecosystem,
and there are many applications
and system processes competing
for CPU time and battery life.
It is our responsibility as
developers in this ecosystem
to do our best to use these
resources efficiently.
Let's pretend the user launches
your app at 3:00 p.m. You want
to make sure you have
a chance to check
in with your server in an hour.
So schedule a task for 4:00
p.m. Well, what happens
if the user launches
your app at 3:50?
We could update our data
now and again at four
when the task runs, but that
does not sound optimal to me.
A better approach is to
use the runtime at 3:50
to reschedule our background
task for an hour later, 4:50.
Every app is different, but
hopefully you can find a pattern
like this to help us
maximize resources.
Okay, let's start
looking at some code.
To help frame our sample
code, we're going to walk
To help frame our sample
code, we're going to walk
through the timeline of
an example application
and show how you can write the
code that corresponds to all
of these life cycle events.
Let's take a look
at a football app,
and pretend that there's
a big game tonight from 7
to 9:00 p.m. We know our user's
favorite team is playing,
and we expect them to be
checking the score frequently.
Let's settle on a
thirty-minute cadence
for our background activity.
The background refresh
API allows only one task
of each type to be in
flight at any given time.
So to start off, let's schedule
our first task for 7:30.
At 7:30, we'll use that runtime
to schedule the next task for 8.
At 8, we'll again
use the runtime
to schedule our next
event for 8:30.
It is important to always make
sure you have a future task
scheduled, or you won't know
when you'll next
get a chance to run.
Here we see the code
for scheduling an
application task on watchOS.
First, let's set the fire date
to thirty minutes from now.
Use the userInfo object
to store some data
about why you made this request.
In this example, I've put the
date at which I made the request
and a reason string
that I can check later
when the task comes back.
This property is optional,
and any secure coding compliant
data can be stored here.
This completion blog
is how you find
out that the system has
successfully scheduled
your task.
Note that just because
the error is nil here,
it does not mean
the task will run
at exactly the requested time.
Austen will talk more about when
and why the system
triggers certain tasks.
With our application
task scheduled,
let's zoom in on our
timeline and look
at only a five-minute window
in which our task
is scheduled to run.
When the system wakes
us, our priority is
to get the latest score
data from our server.
So let's take a look at the code
for starting a background
URLSession on watchOS.
for starting a background
URLSession on watchOS.
First, create a URLSession
configuration object.
It is important that
this object be configured
as a background session because
we're running in the background.
Also, set an identifier
that we'll use later
to access our data.
Next, create a URL session
using this configuration.
We ask the URLSession
to give us one
or more download task
objects where we can associate
as many download tasks as
we want with the session.
Keep in mind the
system will only wake us
when all associated
tasks have finished.
Don't forget to call resume
to start downloading the data.
Getting back to our timeline,
we've got the URL
download in progress.
So it is safe to
complete our task
and allow the application
to sleep.
The system will continue
downloading the data while we
are suspended.
When our data is ready,
URLSession will create a task
When our data is ready,
URLSession will create a task
and wake our application
back up.
But what does wake our
application really mean?
In concrete terms, waking your
application means calling the
new handle background task
method on WKExtensionDelegate.
In addition to this call,
we will receive a
will activate call
on our visible view controllers.
The system coalesces tasks and
delivers them to us as a set.
We need to process all
of the tasks in this set.
So let's get started by
looping through them.
For each task, we can use an
inline task to get an object
of the types we care about.
In this case, we're
processing a URLSession task.
So we need to rejoin the session
using the identifier associated
with the task.
URLSession is a highly
asynchronous API.
We need to be careful
to hold on to our tasks
until we're finished
processing this data.
We recommend you store
the task in a collection
and then drain the
collection when finished,
completing each task to
return it to the system.
Make sure to complete task types
that you don't specifically
handle.
Remember, the system has a
limited number available.
So complete each
one that you get.
We've got our data.
Let's update our model.
You might consider updating
your UI as well at this point,
but we recommend you make use
of this snapshot task runtime
for that type of work.
So before we complete our
URL task, let's make sure
to schedule a snapshot.
With our snapshot scheduled,
it's safe to complete
the URL task
and allow the application
to sleep again.
Soon, the system
will wake us back
up with the snapshot
task we just scheduled.
Now is our chance
to update our UI,
and get everything ready
for the new snapshot.
Snapshots have a unique
completion handler.
So let's take a look at
the completion handler
So let's take a look at
the completion handler
for snapshots on watchOS.
Every application must have
a snapshot at all times.
This is because your snapshot
is both your launch image
and your preview image
while running in the dock.
That rule means that when
we complete a snapshot,
we need to tell the system
how long it is valid for.
Think about your data and
how long it will be relevant
to your users.
In this case, we have another
event scheduled at eight.
So let's set our expiration
for thirty minutes from now.
User info can optionally
store some information
about why we made this request.
That data will return to us
with our next snapshot task.
WatchOS will give your
application an opportunity
to restore its default state
after one hour of inactivity.
You can tell the system
to skip that event
by setting the
restoredDefaultState property
to true.
Doing this lets the system
know that you are already
Doing this lets the system
know that you are already
at your default state, and don't
need an extra task for that.
Apps that have no concept
of a default state should
consider always setting this
property to true.
Once you complete
a snapshot task,
the system will suspend
your application.
Your UI will then be
automatically captured and used
as your new launch image.
This activity will not
wake your application.
We've made it through
an end-to-end example
of a common background refresh
pattern and the associated code.
In case you didn't notice,
even though we were looking
at a whole five minutes
on our timeline,
our application was only
active for 15 total seconds.
By chaining tasks, we were able
to maximize our use
of system resources.
You now have a good
understanding
of what this new API is,
why you should adopt it,
and how you can go
about adopting it.
I'd like to welcome
Austen Green to the stage
I'd like to welcome
Austen Green to the stage
to give you some deeper insights
into how scheduling
works behind the scenes.
Good luck [applause].
>> Hi, everyone.
I'm Austen Green.
I'm a watchOS engineer.
This morning, I would like to
share with you some details
about how scheduling
works behind the scenes.
I'd like to provide some
best practices that we picked
up as we adopted background
refresh in our own applications.
And, finally, I'd like to
close with a quick case study
about specifically how we
adopted background refresh
in our stocks application.
So let's get started.
So the first thing I want
to talk about is runtime.
So while your application
is in the foreground,
you're always scheduled to run.
This means that your
code gets to execute
so that you can do things
like update your model
and draw your UI, and
any other kinds of tasks
and draw your UI, and
any other kinds of tasks
that your application
may need to do.
Now when your application moves
into the background the
system will typically suspend
your application.
This means that your
application doesn't get a chance
to execute any code at all.
Now sometimes while
your application is
in the background, the system
may want your application
to perform a very specific task.
The system will wake your
application and ask you
to perform a specific task
that it may want you to do.
In watchOS 2, there
were several ways
that the system could
wake your application.
For example, to handle a
long look notification,
or perhaps ClockKit would
ask your application
to update its complication.
In watchOS 3, we're adding even
more ways for your application
to run in the background.
Now the system is going to
apply some limits to the amount
of time that you get to run
while in the background.
These limits are on the order of
seconds, and the system is going
These limits are on the order of
seconds, and the system is going
to consider the amount of
time that you use as well
as the amount of CPU you use.
So it's in your best interest
to complete your work as quickly
and as efficiently as possible.
Now in a later seed, if
you exceed these limits,
the system will kill
your application.
You'll get a crash report,
and you'll know whether
you exceeded the CPU limits
or the time limits based
on the exception code
in the crash report.
Now we recognize that different
tasks may have different needs.
So ApplicationRefresh task
and the URLSession task have
a little bit longer limits
than watch connectivity
and your snapshot task.
So in watchOS 2, complications
were the primary way
that your application got
runtime while in the background.
In watchOS 3, we're going to
make sure that you continue
In watchOS 3, we're going to
make sure that you continue
to get multiple updates an hour
if you're a complication
application on par
with what you were
receiving in watchOS 2.
However, if you were previously
asking the system for runtime
to update your complication
data,
you can now request
updates through WKExtension.
I'll show you how to do
that in just a minute.
Also, new in watchOS 3, we're
guaranteeing you fifty pushes
from your parent iPhone if
you're using watch connectivity.
It's really easy to take
advantage of this information
to make sure that you have a
great complication experience
for your users all day long.
Let's take a look at some code.
So let's say that you're running
an iPhone app, and you notice
that your model changed.
You can now query WCSession,
remainingComplication
UserInfoTransfers to figure
out how many high-priority
pushes you have left
for the rest of the day.
You can use this information
to tailor your complication
experience and determine
when the best time is for you
to send your complication data.
So let's say in the
default case,
you've got plenty of pushes.
Go ahead and send
your data immediately.
The user will see your
data that's most relevant
almost immediately.
Now let's say that you've been
pushing a lot, and you're sort
of running low on, on transfers.
So you might consider throttling
the data that you send
to the watch to make sure
that your user will have
complication data updates
throughout the rest of the day.
Finally, if you don't have any
high-priority transfers left,
it's still okay to try and
send this data, however,
the data will get sent
at a lower priority.
Next, I'd like to
talk about some
of the CLKComplication
DataSource methods that we'd
like to move into WatchKit.
If you were previously
asking the system for runtime
If you were previously
asking the system for runtime
with getNextRequested
UpdateDate.
You should now expect the system
to schedule a background refresh
with a preferred
date, the same date
that you were telling
ClockKit previously.
Similarly, when ClockKit
wanted your application to run,
it would call requestedUpdate
DidBegin.
Now we want to do that
at your application level
with handle background refreshed
or handle backgroundTasks.
You'll get an application task
to handle both complication
updates
and your application updates.
Now, new in watchOS 3,
we've introduced the dock.
We think it's a great way
for users to quickly get
at their favorite applications
and have a glanceable view
of all of the information
that they care about.
We want your applications in
the dock to be up to date.
So we're going to
guarantee you a minimum
of one update per hour.
This applies to a snapshot task
and an application refresh task.
This applies to a snapshot task
and an application refresh task.
Now this budget is distributed
across all of the applications
in the dock, and the user can
pick how many applications they
want in their dock.
Consequence of this is that if a
user has fewer apps in the dock,
then your application can
get more opportunities to run
in the background
during any given hour.
Also, we keep your
applications in memory
so that resumes are fast,
and the user can interact
with your application
if they settle on it
as quickly as possible.
Also in the dock,
we have the concept
of a most recently used app.
This application occupies
the last slot in the dock,
and the users are given
an opportunity to keep it
in the dock by pressing
the button.
Now this application
is treated exactly
like a user's favorite
application
that the user has explicitly
added into the dock.
This means that this application
will receive background refresh
tasks and snapshot tasks
like any other application
in the dock.
So you should always make
sure that you schedule
with the system any application,
any background refresh
request that you may need.
Now home screen applications
shouldn't expect
regular scheduling.
So just keep that in mind.
As Eric mentioned
earlier, the snapshots
of your application are
critical to the experience
of your application in
the dock on watchOS 3.
There may be times
when the system needs
to snapshot your application
for various reasons.
Now if the system
asks your application
to perform a snapshot
because we think we need one,
these snapshots don't
count against your budget,
and they're in addition
to the requested snapshots
that you've asked of the system.
There are five triggers
that can cause the system
to ask your application
for a snapshot.
If your complication timeline
updates, if the user interacts
with one of your notifications,
this means that the notification
was actively dismissed,
and it doesn't count if it goes
in the notification center.
When you go from the
foreground to the background,
and then again, one hour later
to give your application
a chance to return
to its default state,
if appropriate.
And, finally, in order to
get everything started,
the system is going to
ask your application
for a snapshot on boot.
This is your opportunity
to start scheduling any other
background refresh tasks
with the system.
Now, I'd like to take
a few minutes to share
with you some best practices
that we picked up along the way
as we adopt a background
refresh in our own applications.
So, first of all, the
system wants to know
as much information as
we can about your needs.
So schedule as often
as you need to.
Every time your application
gets a chance to run,
you should consider
re-evaluating your background
refresh needs and scheduling
with the system as appropriate.
You should not feel
obligated to do work, however.
If the system calls
your application back
for a background refresh task,
and it doesn't make sense,
maybe you just updated
your data already,
need to do anything else,
finish as soon as possible.
Or better yet, in the, in the
past when you've done that work,
consider deferring
any additional work
that you've scheduled
with the system.
You should consider all
the runtime opportunities
that you get to make sure
that you keep your
application up to date.
This means updating
your model and your UI
and scheduling background
tasks for the system.
So for dock and foreground
activations, notifications,
complication updates,
background refresh.
There's any number of reasons
why your application may get
runtime, and you should keep
all of them in mind as you try
and keep your application
up to date.
So application refresh
background tasks is your entry
point into general purpose
runtime while you're
in the background, and we think
there's some great use cases
for this.
You can do things like
pull the system database.
Maybe you need to read
the HealthKit database
or the calendar database
periodically.
You can use this to
schedule future URL sessions.
This is what we do in
our stocks application.
If you have known
time transitions,
you can tell the system the
exact date that you think
that it would be great
to run your application.
For example, a calendar
application
or an itinerary application
may have very well defined
time transitions.
And, finally, if you were
previously getting background
runtime through the ClockKit
API's, we want you to move
to the WatchKit API's to
trigger complication updates.
Now let's talk about some best
practices for your snapshots.
The snapshot is a
system-owned cache
of your application's
data, and like any cache,
that data can become stale.
So the system wants to know
when that data is stale.
You can tell the system
that your snapshot needs
You can tell the system
that your snapshot needs
to be updated by scheduling a
new snapshot request for now.
Now you should think in terms
of significant content change
when you're trying to
invalidate your snapshot.
You wouldn't want
to do something
like high-frequency
invalidation.
For example, in a timer
application that's counting
down, you wouldn't want
to update our snapshot
every single second.
This doesn't make sense.
Instead, you would
want to tell the system
to update your snapshot
when something significant has
happened like the timer's ended.
Now I know this is complex,
and I'd like to share what
I think is a great data flow
for how to manage
this complexity.
So let's say that you
get some external event.
Maybe it's watch connectivity.
Maybe it's NSURLSession.
Maybe you just happened
to run in the foreground
because the user
launched your application.
Basically, anything that causes
you to update your model.
All of the operations
that we want you to do
for background refresh are in
response to your model changes.
For example, updating
your complication,
requesting a new snapshot,
and then evaluating what your
next background refresh needs
are, whether it's for a
background URLSession,
or just scheduling
arbitrary runtime
with a background refresh API.
Now with the dock in watchOS 3,
we think that users
are going to,
we think that users are
going to be in and out
of many applications
much more often
than they were in watchOS 2.
Now in watchOS 2, you
already had to be prepared
to enter the foreground or enter
the background at any time,
but we think these
transitions are going
to happen a lot more often now.
So you should make sure that
you finish any background task
as soon as possible on
foreground activation.
When your application
activates in the foreground,
you don't want to be
doing any additional work.
You just want to do the
work that makes sense
for displaying your
UI to the user.
for displaying your
UI to the user.
Similarly, when you entered
background after being
in the foreground, you should
finish any foreground work
that you were doing
as soon as possible.
Now we recognize that you
might need a little bit of time
to complete any foreground
work, and you can do this
by using NSProcessInfo.
performExpiringActivity.
There's a great session from
last year's WWDC, WatchKit Tips
and Tricks that tells you
exactly how you should
use NSProcessInfo.
performExpiringActivity.
Finally, one more thing I want
to mention, data protection.
Now, typically, a user will put
their watch on in the morning
and unlock it, and the watch
will be unlocked all day long
until they take it off at night,
and put it back on the charger.
Certain types of data
on the watch are completely
inaccessible while the device
is locked.
For example, the most prominent
case is the HealthKit database.
So you should just make sure
that you consider
what your approach is
if your data is not
available for snapshotting.
if your data is not
available for snapshotting.
And then I'd like to
share some testing tips.
The simulator is going to be
great for iterative development.
As I mentioned before,
we have some budgets,
but in a simulator,
we're not going
to enforce any of those budgets.
So you should basically get
your task called at the dates
that you want them
while in the simulator.
Similarly, while
you're on the device,
we may still apply some
budgets, but you're going
to have the best experience
while you're on the charger.
You need to make sure that
you test both the launch path
and the resume path.
The system is going to do its
best to keep your application
in memory, but in the
case of bootstrapping,
the system will have to launch
your application in order
to request the initial snapshot.
Verify that your tasks
are being completed.
In a future seed, you'll get
a crash report if you fail
to complete your tasks in time.
And it's super important that
your application doesn't crash
because we want your
application to be as responsive
because we want your
application to be as responsive
as possible for users.
And, finally, once you think
you have your background refresh
strategy implemented,
you should live on it.
Make sure that you're
getting the experience
that you want your
users to have.
You should vary the number
of applications that are
in your dock to make sure
that you test the best-
and worst-case scenarios for
when you'll be scheduled.
Now, I'd like to share
a quick case study
on how we adopted
background refresh
in our stocks application.
So before we even got
started writing any code,
we took a step back and thought
about the characteristics
that are interesting
for background refresh
for our stocks application.
We use a URLSession to retrieve
server data, and we're going
to have a complication.
This means that we know
that we have multiple views
of our data across the system.
With our complication,
our snapshot,
and now our live application.
We know that we want
to be periodic throughout
part of the day.
We want to get regular
updates for our application,
but then we know something
interesting about our data,
which is that once the
markets closed, our data's good
for the rest of the day.
It's not going to change at all.
Well, let's talk about how this
looks like throughout the day.
So let's say our device boots.
The system is going to ask our
application for a snapshot.
So we'll load our last data,
and we'll prepare our UI,
but before we complete
our snapshot task,
we're going to schedule a
background at URLSession task.
Now this is our opportunity
to start the background
refresh cycle, and make sure
that we can download the most
up-to-date data for our users.
Now we're going to use an
NSURLSession DownloadTask
so that we can give
the system information
about what data we
want to download,
and the system can put
our application to sleep
and the system can put
our application to sleep
and download our data
in the background.
Now URLSession DataTask does
work on a background session,
however, it will fail if your
background app or it will fail
when your application
gets suspended.
And because of the time
limits for background refresh,
your application is likely going
to suspend before your
data is available.
So we could recommend
using the download task.
So a little bit later,
the system is going
to wake our application
up because we finished
our download.
So we're going to
update our model,
and because we've
updated our model,
we're going to do three things.
We're going to trigger
a complication update,
and we're also going
to tell the system
that our snapshot
is invalid by asking
for a new snapshot right now,
and then we're also going
to evaluate what our next
background refresh needs are.
So we'll figure out what the
next time we want to run is,
and we'll tell the system that.
Now a little bit later, we get
to run for background refresh,
Now a little bit later, we get
to run for background refresh,
and all we're doing here
is scheduling our next
URLSession download.
So we complete this cycle
several times thoughout the day.
Just keeping our
application up to date,
the system will snapshot us, and
if the user views our snapshot
in the dock, we'll have the
most recent data available
in our snapshot.
Well, let's say that the user
activates our app from the dock.
So we go full screen,
and we want to make sure
that our users have the
most up-to-date data.
So we'll download the
most up-to-date data again
because we've entered
the foreground.
And, and once we've updated our
model, we still do three things.
We request a complication
update,
we request a new snapshot,
and then we schedule a
background refresh again
for a later time.
Now there's two things I
want to point out here.
First of all, we're
in the foreground,
but we're still requesting
a new snapshot.
This is absolutely okay, and we
really expect you to do this.
We want you to request a
new snapshot whenever your
model changes.
The system is smart
enough to know
when your application's
foreground,
and when it's not okay for us
to send you a snapshot task.
The second thing is because
we run in the foreground
and updated our model,
it makes sense for us
to evaluate our next
before refresh needs.
If we knew that we were
probably going to run
in the next ten minutes, but
we've just downloaded our data,
we can defer our snap, or we
can defer our background refresh
request with the system
to maximize the amount
of time that we get to run.
To maximize the number
of opportunities
that we get to run.
Finally, the last update
after market closes.
We know our data stopped
changing for the day,
but we'll complete
our update as normal.
This means updating
our complication,
requesting a new snapshot,
and then evaluating our
background refresh needs.
So because we know our data
stopped updating for the day,
that we can't have stale data
in our complications
or our snapshots.
in our complications
or our snapshots.
We can wait until
the next market open
for the next background
refresh opportunity.
This lets our application get
out of the way of the system
and not do any unnecessary work,
which means that there's
more refresh tasks
for other applications
on the system.
So to summarize,
complete your tasks.
It's absolutely critical
to complete your tasks.
If you don't, in a future
seed, the system is going
to kill your application.
If the system kills
your application,
users won't have the quick
response times in the dock
that they're expecting,
and users will take your
applications out of the dock.
Use all the runtime that
you get efficiently.
Consider foreground activations,
notifications, ClockKit, and,
of course, the background
refresh opportunities to run.
Anytime you get runtime,
make sure that you consider
keeping your model up to date
and evaluating your background
refresh needs with the system.
and evaluating your background
refresh needs with the system.
Tell the system when
your data changes.
Your complication and your
application snapshot are both
system-owned caches of
your application's data.
The system needs to know when
that data is no longer valid
so that we won't display the
wrong things for the user.
Users expect to see consistent
data no matter how they view
your application's data.
And, finally, you need
to consider your
adoption strategies
on a case-by-case basis.
There is no one size
fits all solution.
You have to really consider how
users are using your application
and interesting characteristics
about your data
for how you plan your
background refresh strategy.
For more information, you
can visit this website,
and there is some great related
sessions this afternoon at 3:00,
Architecting for
Performance on watchOS 3.
We'll go into some more
detail about what we did
in the stocks application.
Thank you very much.