Keeping your Apple Watch app up to date is key to creating a great experience on watchOS 3. Learn how to use the new background tasks to keep your complications and the new watchOS 3 Dock snapshots consistent with your app's underlying model. Discover how to get the most from NSURLSessions and Watch Connectivity to keep data fresh and glanceable.
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
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.
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.
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?
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
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.
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,
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.
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
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
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.
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
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
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
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
to give you some deeper insights
into how scheduling works behind the scenes.
Good luck [applause].
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
that your application may need to do.
Now when your application moves
into the background the system will typically suspend
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
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
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
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
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.
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
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
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
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
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.
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.
There's a great session from last year's WWDC, WatchKit Tips
and Tricks that tells you exactly how you should
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
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.
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
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 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,
and all we're doing here is scheduling our next
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
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.
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.
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.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.