Data is a complex part of any app, but SwiftUI makes it easy to ensure a smooth, data-driven experience from prototyping to production. Discover @State and @Binding, two powerful tools that can preserve and seamlessly update your Source of Truth. We'll also show you how ObservableObject lets you connect your views to your data model. Learn about some tricky challenges and cool new ways to solve them — directly from the experts!
To get the most out of this session, you should be familiar with SwiftUI. Watch “App essentials in SwiftUI” and "Introduction to SwiftUI"
Hello and welcome to WWDC. Hello and welcome to Data Essentials in SwiftUI.
I'm Curt Clifton, an engineer on the SwiftUI team. Later I'll be joined by my friends and colleagues Luca Bernardi and Raj Ramamurthy. We're going to cover three main areas in this talk. I'll talk about getting started on the data flow in your SwiftUI app, and cover topics like State and Binding.
Then Luca will discuss how you can build on those ideas, and more, to design the data model for your app. Finally Raj will share techniques for integrating your data model into your app. Along the way we'll discuss the lifecycle of a SwiftUI view and share several cool new features that make it even easier to model your data. We'll also help you develop a deeper understanding of how value and reference types in Swift interact with data flow in SwiftUI.
I'll be walking through some basic data flow features in SwiftUI and will cover some questions you should ask yourself whenever you create a new SwiftUI view. Luca is really into book clubs. He's so into them that he decided he needed an app to keep track of what each of his clubs is reading and take some notes for their next meeting. I enjoy reading too and thought it would be fun to work on an app together. To get started I want to prototype the view that represents a book I'm reading. When I start on a new view in SwiftUI there are three key questions I like to think about. What data does this view need to do its job? In this example, the view needs a thumbnail of the book cover, the title, the author's name, and the percentage of the book that I've read. How will the view manipulate that data? This view just needs to display the data. It doesn't change it. Where will the data come from? This is the Source of Truth. In the examples throughout this talk, Luca, Raj, and I will use this badge to label the Source of Truth.
Ultimately, as we'll see, this question of the Source of Truth is the most important one in the design of your data model. Let's build out this view and see what its Source of Truth should be. So, what data does this view need to do its job? The book value provides the name of the cover image, the author, and the title. The progress value provides the percent complete.
And how will the view manipulate this data? It just displays the data. It doesn't change it. So these can be let properties. And where will the data come from? It will be passed in from the superview when the BookCard is instantiated. The Source of Truth is somewhere farther up the view hierarchy.
The super view passes the 'true data' in when it instantiates a BookCard.
A new book card is instantiated every time the superview's body executes.
The instance lives just long enough for SwiftUI to render it, then it's gone.
We can visualize the internal structure using a diagram. The boxes on the left represent the SwiftUI views that are composed to build this BookCard.
The capsules on the right represent the data that's used to render the views. We'll return to diagrams like this throughout the talk. Next I'd like to look at a slightly more interesting view. When I tap on a book the app takes me to this screen where I can review my progress. I want to add a way to update my progress and add notes when I tap on the update progress button. Something like this. Let's look at how the parent view and this sheet work together. We'll focus on how the sheet is presented.
When the user taps the update progress button we'll call the present editor method.
It will mutate some state to cause the sheet to appear. What data does this view need to control the presentation of the sheet? We need a Boolean to keep track of whether the sheet is presented and we need a String to keep track of the note and a Double to track the progress. Whenever I have multiple related properties like this, I like to pull them out into their own struct. Besides making BookView more readable, there are two other great things about this approach. We get all the benefits of encapsulation: EditorConfig can maintain invariants on its properties and be tested independently.
And because EditorConfig is a value type, any change to a property of EditorConfig, like its progress, is visible as a change to EditorConfig itself. Our next question is "How will the view manipulate this data?". When the Update button is tapped we'll need to set 'is editor presented' to true and update progress to match the current progress. Because we extracted the state into the editor config struct we can make it responsible for those updates and just have the BookView ask the EditorConfig to do the work. Then we'll add a mutating method to EditorConfig like so. And where will the data come from? Well the editor configuration is local to this view. There isn't some parent view that can pass it in. So we need to establish a local Source of Truth. The simplest Source of Truth in SwiftUI is state. When we mark this property as state SwiftUI takes over managing its storage. Let's look at that as a diagram. Again we have the views represented by these boxes on the left and the data by a capsule on the right. Notice that the capsule has a thick border. I'm using this border to indicate data that's managed by SwiftUI for us. Why is that important? Well remember that our views only exist transiently. After SwiftUI completes a rendering pass the structs themselves go away. But because we mark this property as state, SwiftUI maintains it for us. The next time the framework needs to render this view it reinstantiates the structs and reconnects it to the existing storage.
Let's look at the ProgressEditor next. What data does the ProgressEditor need to do its job? Well all the data from an EditorConfig. And how will the view manipulate that data? It needs to change it. So we'll use a var.
And where will the data come from? That's an interesting question in this case.
Back to the diagrams. Let's focus on the BookView and the ProgressEditor.
Suppose we just passed the EditorConfig down to the ProgressEditor as a regular property. Because EditorConfig is a value type, Swift would make a new copy of the value. Any changes the ProgressEditor made to the note or the progress would only change this new copy, not the original value that SwiftUI is managing for us. So this doesn't allow ProgressEditor to communicate with BookView. What next? What if we gave ProgressEditor it's own state property? That seems like it might be what we want. It tells SwiftUI to manage a new piece of data for us. Sadly this is also wrong. Remember state creates a new Source of Truth. Any changes made by the ProgressEditor would be made to its own state, not the one shared with BookView. We want a single Source of Truth. We need a way to share right access to the Source of Truth from BookView with ProgressEditor. In SwiftUI the tool for sharing right access to any Source of Truth is binding. BookView creates a binding to EditorConfig - a rewrite reference to the existing data - and shares that reference with ProgressEditor. By updating the EditorConfig through this binding the ProgressEditor is mutating the same state the BookView is using.
SwiftUI notices changes to the EditorConfig and knows that both BookView and ProgressEditor have a dependency on that value and so it knows to re-render those views when the value changes. The ProgressEditor needs to pass data back to the BookView. We've just seen that bindings are the right tool for this task. The dollar sign in the call creates a binding from the state because the projected value of the state property wrapper is a binding. The binding property wrapper creates a data dependency between the ProgressEditor and the EditorConfig state in BookView. Many built-in SwiftUI controls also take bindings. For example the new text editor control used for our notes takes a binding to a string value. Using the dollar sign projected value accessor, we can get a new binding to the note within the EditorConfig. SwiftUI lets us build a new binding from an existing binding. Remember bindings aren't just for state. That's a bit on getting started with data flow in SwiftUI. Remember to ask yourself the three questions when adding a SwiftUI view. What data does this view need? How will it use that data? And where does the data come from? You can use properties for data that doesn't change. Use state for transient data owned by the view. Use binding for mutating data owned by another view. Now I'd like to turn things over to Luca to dive into designing your data model because state is not the whole story.
Thank you, Curt! Ciao everyone, my name is Luca. My colleague Curt has just described how to use state and binding to drive changes in your UI and how these tools are a great way to quickly iterate on your view code. But state is designed for transient UI state that is local to a view. In this section I want to move your attention to designing your model and explain all the tools that SwiftUI provides to you. Typically in your app you store and process data by using a data model that is separate from its UI. This is when you reach a critical point where you need to manage the life cycle of your data including persisting and syncing it, handle side-effects, and more generally integrate it with existing components. This is when you should use ObservableObject. First let's take a look at how ObservableObject is defined. It's a class constraint protocol which means it can only be adopted by reference types. It has a single requirement: an objectWillChange property. ObjectWillChange is a Publisher, and as the name suggests, the semantic requirement of the ObservableObject protocol is that the publisher has to emit before any mutation is applied to the object.
By default you get a publisher that works great out of the box but if you need to you can provide a custom publisher. For example you can use a publisher for a timer or use a KVO publisher to observe your existing model.
Now that we've seen the protocol let's take a look at the mental model for understanding ObservableObject. When your type conforms to ObservableObject you are creating a new Source of Truth and teaching SwiftUI how to react to changes. In other words you are defining the data that the view needs to render its UI and perform its logic. SwiftUI will establish a dependency between your data and your view, here presented with blue boxes.
SwiftUI uses this dependency to automatically keep your view consistent and show the correct representation of your data. We like to think of ObservableObject as your data dependency surface. This is the part of your model that exposes data to your view but is not necessarily the full model. If you think of ObservableObject this way it doesn't need to be exactly your data model. You can separate your data from its storage and lifecycle.
You can model your data using value type and manage its lifecycle inside effect with a reference type. For example you can have a single observable object that centralizes your entire data model and is shared by all your view.
Like in the diagram here, this gives you a single place for all your logic making it easy to reason about all the possible state and mutation in your app.
Or you can focus on part of your app by having multiple ObservableObject that offer a specific projection onto your data model and are designed to expose just the data that is needed. This works better when you have a complex data model and you want to provide a more tightly scoping validation to part of your app. Let's go back to the app we were building and let's see how you can apply what we have just discussed. Let's bring back the view that Curt was working on before. This is the view that allows me to update my progress in the book and add some note of things I found interesting during my reading section. Curt focused on the data for the progress sheet.
Let's look at the rest of the data we need for this view and how to use ObservableObject to add rich features such as storing data on disk or syncing it with iCloud. We can create a new class called CurrentlyReading that conforms to ObservableObject that stashes a book and its reading progress.
This is the part of our model that we will expose to our view to present data and respond to changes. The specific book will never change so we can just make this property a let. We want to be able to update the progress and have our UI react to it. We can do this just by annotating the progress property with the @Published property wrapper. Let's take a look at how @Published works. @Published is a property wrapper which makes a property observable by exposing a Publisher. For most models, you can just conform to ObservableObject, add @Published to the property that might change and you're done. It's that simple to never have to worry about keeping your data in sync with your view. When you use @Published with a default observable object publisher, the system will automatically perform invalidation by publishing right before the value changes. For advanced use case the projected value of @Published is a publisher that you can use to build reactive streams. Let's revisit the three question they should be asking when designing your data model. With ObservableObject, answering the second question is pretty straightforward: we always assume mutability.
Let's now take a look at how to answer these other two questions when it comes to ObservableObject. We've seen how to define our model. But now we need to use it in our view. SwiftUI offers three property wrapper that you can use in a view to create a dependency to an ObservableObject. These tools are ObservedObject, StateObject which is new this year, and EnvironmentObject.
Let's start by taking a look at ObservedObject. ObserveObject is a property wrapper that you can use to annotate properties of your view that hold a type conforming to ObservableObject. Using it informs SwiftUI to start tracking the property as a dependency for the view. You'll define the data that this view will need to do its job. This is the most simple and flexible of the tool. ObservedObject does not get ownership of the instance you're providing to it. It's your responsibility to manage its lifecycle.
Let's see how to use it in our app. Here I have my BookView. It's the view that displays the book and all the progress I've logged so far. From the screen I can also update my progress for this book. We can add a property type CurrentlyReading, the type we have just created, and annotate with it @ObservedObject property wrapper. The instance that is assigned to this property is going to be the Source of Truth for this view. Now we can read the model in the view body. SwiftUI will guarantee that the view is always up to date. There is no code that you have to write.
And there is no event to manage to keep your view in sync. You can just declaratively describe how to drive the view from the data and SwiftUI will take care of all the rest. My colleague Raj will go into more detail about SwiftUI update lifecycle but I want to take you behind the scene and show you what SwiftUI is doing for you. Whenever you use ObserveObject SwiftUI will subscribe to the objectWillChange of that specific ObservableObject. Now whenever the ObservableObject will change all the view that depends on it will be updated. One of the questions that we often get is "why will change? Why not did change?". And the reason is that SwiftUI needs to know when something is about to change so that it can coalesce every change into single update. But how do we produce mutation? Many of the UI components vended by SwiftUI take a Binding to a piece of data and, earlier in the talk, you have seen an example of how to design your component to do the same. This is one of the fundamental design principle of SwiftUI.
Accepting a binding allows a component to read and write access to a piece of data while preserving a single source of truth. Curt has shown you how to derive a binding from state and doing the same with ObservableObject is just as easy. You can get a Binding from any property that is of value type on an ObservableObject just by adding the dollar sign prefix in front of your variable and accessing the property. Let's see a concrete example in our book club app. One of the great satisfaction when reading a book is finishing that last chapter and I want a grand gesture to mark this event.
I can't think of anything better than tapping on a toggle to say "I'm done with this book". The first thing I need to change is my model. We can just add a new property isFinished and annotate it with the @Published so that whenever its value changes, our UI will reflect the change. Let's see how we can change BookView to add this feature. I can add a toggle with a nice label to allow me to mark "This book is done". The toggle expects a binding so that it can show the current state and when the user taps on it, it can mutate the value. We can provide a Binding to isFinished just by adding the dollar sign prefix to currentlyReading and accessing the isFinished property. Now whenever the user interact with the toggle CurrentlyReading will be updated and SwiftUI will update all the view that depends on it. For example in this view we will disable the button to update the progress when we are done reading the book. Throughout our app we are shown this beautiful book cover and we want to load them asynchronously from the network, just before they are displayed on screen. They're expensive resources.
So we want to keep them alive only while the view is visible. More generally we notice that often you do want to tie the lifecycle of your ObservableObject to your view like with state. If you recall, ObserveObject does not own the lifecycle of its ObservableObject. And so we wanted to provide a more economic tool. This tool is state object, which is new this year.
When you annotate a property with state object you provide the initial value and SwiftUI will instantiate that value just before running body for the first time. SwiftUI will keep the object alive for the whole lifecycle of the view. This is a great addition to SwiftUI. Let's see how we can use it in practice. Let's create a CoverImageLoader class to load a specific image by name. Here I'm just showing the skeleton of this class but note how I made it an ObservableObject and annotated the property that holds the image with a@Published. Once we have our image SwiftUI will automatically update the view. And now in our view we can use CoverImageLoader and just annotate the property with StateObject. CoverImageLoader will not be instantiated when the view is created. Instead it will be instantiated just before body runs and kept alive for the whole view lifecycle. When the view is not needed anymore, SwiftUI will release the CoverImageLoader as expected. You don't need to fiddle with OnDisappear anymore! Instead, you can use the ObservableObject lifetime to manage your resources.
In SwiftUI, views are very cheap. We really encourage you to make them your primary encapsulation mechanism and create small views that are simple to understand and reuse. This means that you might end up with a deep and wide view hierarchy, like in the diagram here. If we look at this through the perspective of data flow, you might need to create an ObservableObject high up in the view hierarchy and pass the same instance to many views.
Sometimes you need to use your ObservableObject in a distant subview and passing it down through views that don't need the data can be cumbersome and involve a lot of boilerplate. Luckily we have a solution for this problem with EnvironmentObject. EnvironmentObject is both a view modifier and a property wrapper. You use the view modifier in a parent view where you want to inject an ObservableObject. And you use the property wrapper in all the views where you want to read an instance of that specific ObservableObject.
The framework will take care of passing that value everywhere it's needed and track it as a dependency only where it is read. In this part of the talk we have seen how to design your model using ObservableObject and how SwiftUI provides all the fundamental primitives that you can use to build the best architecture for your needs. We've seen how to create a dependency between a view and a piece of data, how with a new StateObject property wrapper you can tie the life cycle of ObservableObject to a view, and finally, how EnvironmentObject gives you the convenience to flow ObservableObject in your view hierarchy. Now I'm going to end it over to Raj. He's going to dive deep into SwiftUI's view life cycle and how it relates to performance, how to handle side effects, and some exciting new tools. Thank you everyone and have a great WWDC - Raj.
Thanks Luca. You've learned how to get started with data in SwiftUI and how to design a great model. Now I'd like to tell you how to design for the best performance as well as some further considerations in choosing a source of truth. To begin with, let's talk about views and their role in the SwiftUI system. A view is simply a definition of a piece of UI. SwiftUI uses this definition to create the appropriate rendering. SwiftUI manages the identity and the lifetime of your views. And because a view defines a piece of UI, they should be lightweight and inexpensive. In the book club app, like in every app, everything on screen is a view. Note that the lifetime of a view is separate from the lifetime of the struct that defines it. The struct you create that conforms to the view protocol actually has a very short lifetime.
SwiftUI uses it to create a rendering, and then it's gone. Let's use a diagram to illustrate the importance of making views lightweight. This diagram shows the SwiftUI update lifecycle. Starting at the top, we have your UI. Moving counterclockwise, an event comes in, which causes some closure or action to run. That then results in a mutation of a Source of Truth.
Then once we've mutated the Source of Truth, we'll get a new copy of the view, which we'll use to produce a rendering. That rendering is your UI.
That's just the basics. We'll revisit this diagram in a bit.
For now, let's simplify it ... and a little bit more ...oh much better! As the name implies this life cycle is a cycle. It keeps repeating many times while your app is running. This cycle is also really important for performance.
And ideally the cycle carries on smoothly, like this.
But if there's expensive, blocking work at any of these points, the performance of your app will suffer. We call this a slow update. It means you might drop frames or your app might hang. So how do you avoid slow updates? Well the first thing you can do to avoid slow updates is to ensure that your view initialization is cheap. A view's body should be a pure function, free of side effects. That means you should simply create your view description and return. No dispatching, no other work. Just create some views and move on.
Avoid making assumptions about when and how often body is called. Remember SwiftUI can be pretty smart sometimes, which means it might not call body in line with your assumptions. To illustrate the importance of body being cheap, let's look at an example. Here's a simplified example of what our currently reading list might look like. In the reading list viewer, we define body as a NavigationView with the ReadingList within. Then in ReadingList we'll use an ObservedObject to generate the data. This seems pretty reasonable, but there's actually a bug lurking here. Can you see it? It turns out whenever the body of ReadingListViewer is created, you're going to incur a repeated heap allocation of ReadingListStore. And this can cause a slow update! Remember from earlier that your view structs do not have a defined lifetime. So when you write this you're actually going to create a new copy of the object every time.
And a repeated heap allocation like this can be expensive and slow. It also causes data loss because the object is reset every time. OK so we've identified a problem. But how do we fix it? Well in the past you had to create the model somewhere else and pass it in. But wouldn't it be great if you could just do this inline? I'm happy to tell you that this year we have a tool to solve this problem, called StateObject. And as Luca explained earlier, StateObject lets SwiftUI instantiate your ObservableObjects at the right time, so you don't incur unnecessary heap allocations and you don't lose data. This means you can get great performance and correctness! One thing to note: we are declaring a new source of truth here, so let's slap the badge on it.
Alright, let's bring back the diagram again. And .. enhance. Great.
One thing to note is that there are multiple sources of the events at the top left. Your app might react to an event generated by user interaction, such as tapping a button, or it might react to a publisher firing, like a timer or a notification. Regardless of what triggers the event, the cycle is still the same. We'll mutate a Source of Truth, update the view, and then produce a new rendering. These triggers are called event sources. They are the drivers of change in your views.
As I mentioned, a good example of this is user interaction, or a publisher such as a timer. And new this year, we have new ways to react to events, such as changes to the Environment and Bindings, and new ways to handle URLs and user activities.
Each of these modifiers takes a parameter such as a publisher or a value to compare. And it also takes a closure. SwiftUI will run the closure at the right time to help you avoid slow updates and keep body cheap.
However, note that SwiftUI will run these closures on the main thread, so if you need to do expensive work, consider dispatching to a background queue.
We're not going to go into detail on these today, but I encourage you to check out the documentation to learn more. So that's a bit on how to avoid slow updates and how to design for great performance. Next let's bring back those three questions. So we've largely covered how to solve the first two questions. But the third one isn't as easy. When you answer this question you're making a decision about the Source of Truth that you're going to use. And this is a hard question! There is no one right answer here, so to help, I'd like to walk through some considerations. An important question to ask is "who owns the data?" Is it the view that uses the data? Or maybe an ancestor of that view? Perhaps it's even another subsystem of your app. A few guidelines here: as mentioned earlier, share data with a common ancestor. Also prefer StateObject as a view-owned Source of Truth for your ObservableObjects. Lastly, consider placing global data in the app. We'll cover this next.
Now let's talk about data lifetime. We'll cover tying data lifetimes to views, scenes and apps. For more on SwiftUI scenes and apps, please refer to the App Essentials in SwiftUI session. First let's start with Views. As we've shown you throughout this talk, Views are a great tool to tie your data lifetime to. And all of the property wrappers we've discussed today work with Views. You can make use of the State and StateObject property wrappers to tie data lifetime to View lifetime. Next let's talk about Scenes. Because SwiftUI's Scenes each have a unique view tree, you can hang important pieces of data off the root of the tree. For example you can put a Source of Truth on the view inside of a WindowGroup. In doing so, each instance of the scene that the WindowGroup creates can have its own, independent Source of Truth that serves as a lens onto the underlying data model. This works great with multiple windows.
As you can see here, the two scenes have independent UI states that represent the same underlying data. So now Luca can go to two online book clubs at the same time! Next let's talk about Apps.
Apps are a powerful new tool this year in SwiftUI allowing you to write your entire app in just SwiftUI. But what's great about Apps is that you can use State and other Sources of Truth in an App just like you do in a View.
Let me show you an example. Here we'll create a global book model for our entire app by using the StateObject property wrapper. Whenever the model changes, all of our app's scenes, and consequently all of their views, will update. And by writing this, we've created an app-wide Source of Truth. When considering where to put your Source of Truth, you might want to put it in the App if it represents truly global data. Your data's lifetime is important, but that lifetime is tied to the lifetime of its Source of Truth. And in all of the previous examples we've used tools like State, StateObject, and Constants.
But these have a limitation, which is that they're tied to the process lifetime.
Which means if your app gets killed, or the device restarts, State won't come back. To help solve this problem, new this year, we're introducing Storage.
These have an extended lifetime and are saved and restored automatically.
Note these are not your model. Rather, they are lightweight stores that you use in conjunction with your model. Let's start by taking a look at SceneStorage. SceneStorage is a per-Scene scoped property wrapper that reads and writes data completely managed by SwiftUI. It is only accessible from within Views, which makes it a great candidate for storing lightweight information about the current state of your app. Let's take a look at an example.
Here's the book club app from earlier with two scenes side by side. The first thing to think about when using SceneStorage is: what do you really need to restore? In this case, all we need to save and restore is the selection.
The names of the book, progress, and the notes are all stored in the model- so we don't need to save and restore those. Let's jump to code. Here you can see how we use SceneStorage to save and restore our selected state. We'll pass a key, which must be unique to the type of data we're storing. Then, we can use it just like State. SwiftUI will automatically save and restore the value on our behalf. And since this behaves like State, we've actually declared a new Source of Truth here. And this time it's a scene-wide Source of Truth. Now, if the device restarts, or the system needs to reclaim resources backing a scene, the data will be available at the next launch, allowing Luca to pick up his book club activities right from where he left off. Now that you've seen SceneStorage in action, I'd like to discuss AppStorage. This is app-scoped global storage which is persisted using user defaults. It's usable from anywhere, so you can access it from within your App or from within your View. AppStorage, like user defaults, is super useful for storing small bits of data, such as settings. In our book club app, we've also decided to introduce some settings. Let's take a look at how to use AppStorage to accomplish this.
In our Settings View, all we need to do is add the AppStorage property wrapper and give it a key. By default, this uses the standard user defaults, but you can customize it if you need to. For more information please refer to the documentation. In this case we'll set up an AppStorage for each of our two settings here. We'll give them each a unique key because they're independent pieces of data. When using SceneStorage and AppStorage, it's important that unique pieces of data have unique keys. And just like the other property wrappers, this is also a Source of Truth, which means that we can get Bindings to it, such as for use in a Toggle. And now, whenever the data changes, it will automatically be saved and restored to and from user defaults. We've seen a variety of tools today for process lifetime and extended lifetime, and you use each of the tools here to store UI level state. For the storage types, please be careful not to store everything with them, because persistence isn't free. I'd like to also call out one more tool and that's ObservableObject. We've designed ObservableObject to be very flexible, so you can use it to achieve super custom behaviors, such as backing the data by a server or by another service. And together, these tools form a family that gives you a high degree of freedom to choose what best suits your needs. We've seen a lot of tools and uses of them today, but the main takeaway is that there isn't a one-size-fits-all tool.
Each has its own set of traits, so a typical app will use a variety of tools.
We've done just that in our book club app. We've used State for buttons and our progress view, StateObject for our currently reading model, SceneStorage for our selection, and AppStorage for our settings. It's important to think about what the properties of your data are and what the right Source of Truth to use is. And you should also try and limit the number of Sources of Truth to cut down on complexity. And finally, take advantage of Bindings as a way to build reusable components. Remember, bindings are completely agnostic to their Source of Truth, which makes them a powerful tool for building clean abstractions. Now that you've learned the essentials, it's time to build a great model. Thank you,
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.