Azam Sharp provides a surgical clarification on SwiftData's background execution that most developers only learn after their first production crash. It is a vital lesson in distinguishing between UI-bound tasks and true persistent concurrency.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
SwiftData Background Tasks: What Actually HappensAdded:
Hello everyone and welcome to Awesome Shark School and in this video, I'm going to cover one of the ways that you can download the data from an API and then insert it into SQL Lite using Swift Data framework. Now, obviously there are many many many different ways that you can do that, but we're going to cover one of the scenarios and maybe in the future videos I can cover some other scenarios.
Now, this video is brought to you by my brand new book Swift UI architecture patterns and practices for building scalable application. It is available as an ebook as well as a paperback book.
You can see all the different chapters that are available.
It has Swift data architecture also validation, navigation, testing, performance, debugging and you can also check out some of the reviews of the people who bought it. So, thank you so much for your continuous support.
Let's go ahead and get started.
So, what kind of data we're going to be dealing with? So, this is the earthquake.usgs.gov and you can see that this is a feed of all the different earthquakes. Now, you can see it's actually taking a long time to to even load.
So, this is like probably 11,200 different points. You can see over here properties, magnitude, place, time, updated. So, this like now like 11,000 different earthquakes. All right? And you can see it's taking a long time to load also. All right?
Anyway, so this is the data that we will be using.
Now, in order for this data to work, we will need to create some sort of DTOs, right? [snorts] Because the data for the earthquake, you know, it is basically structured in a way that you have obviously a root element, then you have metadata, then you have features, properties and so on.
So, the best way would be to just create a DTO. So, I'm going to go ahead and add a new folder DTOs.
All right?
And inside over here, I can probably create a new file.
You can create a single file also or you can create multiple files each for your own different DTO, but I'm just going to create a single file and I'm just going to go ahead and basically copy all the stuff because I don't want to create the DTO.
These DTOs were actually created by ChatGPT anyways. So, this is what it looks like.
All right? I mean, some of the properties I've actually added like the event date and updated date and all that stuff, but yes, it was mostly created with ChatGPT.
Okay. So, this looks fine. Now, the next thing that we want to do is we want to create the model, right? The Swift data model. So, let's go ahead and create the Swift data model. I'll put it in the model folder. Again, it's completely up to you how you organize it.
For this, I can add a new file earth quake and I'm showing you from the beginning because even though I might like copy paste code for the API and all that stuff, but at least you will have a better idea.
Earthquake model, what does that look like?
Here we go.
But the first thing you will notice is that since it's a Swift data model, it is using the model macro.
Class is earthquake.
And this is a kind of like an interesting thing because each earthquake comes with a code and the code has to be unique. So, we are putting a unique constraint on it.
We have other things like magnitude, time, place and all that stuff you can see over here.
So, this means all of these things will be persisted into the database. That's the That's what we want to do.
The next thing that we want to do is the networking part of it.
Right? So, let me go ahead and create a different folder. Like how are we going to download that data?
So, let's go ahead and create a new file from a template.
Earth quake client.
Again, this is going to be simp super simple.
There we go. Earthquake client. We will have a single function called load feed and it is going to return you the top DTO which is the earthquake feed DTO.
This is the URL, the one that I already showed you.
And it's going to decode it and return it and that's it.
And earthquake client is a service which is a stateless service also.
You can see that it does not really have any properties of its own. It does not really maintain any state. It just calls this load feed and it returns you the feed DTO.
The next thing is important one. That's the actual import service, right? So, let's go ahead and put that into a services folder.
And I'm going to go ahead and say There we go. We'll call it import earth quake service.
So, the job of the earthquake service or the import earthquake service as the name suggests is to import the data, right?
And again, I'm going to make this as a import stateless service.
We will have a simple function and we can actually create a static function because you know, it's not really maintaining any state.
It's more like a utility function. So, earthquake.
Now, this is where it becomes interesting.
In order for the import earthquakes to work, this function to work, it needs two different things, right? It needs to get all the data from the API which means from the earthquake client and it also needs a way to persist the data into the database. So, for that, it will need the model container.
So, let's go ahead and pass that as the first thing. So, I'll say container which will be model container. And the second will be the earthquake client.
So, I'm going to say earthquake client which will be client.
This is going to be an async function.
It can throws.
All right.
Now, let's go ahead and write our code over here. The first thing we're going to do is we're going to load earthquake feed because we need the data. So, we're going to get the data using the earthquake client.loadFeed.
So, that's going to be really simple because load feed [snorts] is going to give us all the different well, earthquakes from the US data USGS data.
Next, we can actually go through this.
Features.
All right?
We can get the coordinates.
This is where you will construct your earthquake. Now, again, creating the earthquake because earthquake does require a lot of different parameters. You can see we are passing the magnitude. If the magnitude is nothing, we pass in like zero or something like that. But if you don't really like the default values, then you can make like a guard statement over here and skip those things if you want to.
Next, we're going to say container dot or, you know, just to make our life a little bit easier, I can say over here container dot main context. Interesting. So, remember that main context because we're going to come back to that later.
We're going to insert our earthquake model in there. Now, keep in mind that when you are inserting you know, earthquake into the context, then it doesn't really mean that it's going to be saved automatically.
All right?
Now, since it's a Swift UI application, it is going to wait for certain kind of events like maybe, you know, the context is it has all the earthquakes and when you try to go in the background, you push the app into the background, then it will save it or when you navigate to a different screen, then it save it. But I think a better idea in this case will be simply to save it yourself.
So, that can become like a really simple way of doing things. All [snorts] right?
Now, this is We'll come back to this a little bit later because there's so many different variations of this, right? Um if you run this as it is right now, it's going to get all the earthquakes.
It's going to get into get the main context.
Okay, note this. Note this.
And then it's going to create the earthquakes, insert it into the context and then save it.
What if I run it again? Like what will happen if I run it again? Well, it's still going to load the feed and then it's going to get the main context, try to insert it again.
But when it tries to insert it again, it will start failing.
Not failing as in crashing the app, but if you look over here, we have a unique constraint on the code. So, if we are pulling the same list of earthquakes and you know, for the code, then you know, when you try to insert, it's going to break that constraint and it's going to just >> [snorts] >> say that, well, you can't really do that because that code already exists.
Now, it's up to you if you want to use that approach or not.
The other approach that we can do is maybe, you know, you can create a function, which is already imported function.
Where you are going to pass in the context, which will be model context.
And we're simply going to return you a Boolean value.
And over here, we're going to check that if the earthquakes are already imported or not.
All right?
Oh, uh private it comes over here.
So, now we have this function called already imported.
And this function is basically checking that even if a single earthquake is there, even if a single earthquake, you see that? One.
Then I'm not going to do the job.
All right? So, I can go over here, probably at the very start. Actually, let's move this a little bit on the top.
Oh, I don't know what's going on over here. I just copied this line.
There we go.
And we don't really need it over here.
Okay. So, over here we can probably check.
Already imported.
And then we send in the context, else return.
All right?
So, this means that if it is not already imported, then you do all of this stuff.
But if even a single earthquake is in the database, then don't do it.
I mean, this is just one of the scenarios, right? I mean, the previous one was that we're going to try to import everything again and it's going to start failing because of the unique constraint that we have. So, this is a kind of like a second kind of a scenario is that we're not really going to try to import. Even if we find one earthquake in the database, we're done.
We're not going to do it again.
But again, obviously this is scenario based, right?
Maybe you only imported like five and then the app crashed.
So, now it's never going to import those things because well, uh because you are saying over here even if you imported one, then I'm not going to do anything after that.
All right? So, it's completely up to you. You can remove that, you can have that, you know, there's so many different variations. So many different variations.
So, now the question becomes, okay, where do we call this? Where do we call import earthquake service? And these kind of things usually happens when you start the app. So, I'm going to go into jump into the app file.
So, if data and let's container And this is not the only way, by the way, that I've mentioned like number of times, right? I mean, this is just two different ways and there are so many other ways that you can do that.
I'm actually working on a book on Swift data right now. It's not even ready, but in the book, I'm going to go through multiple different ways for background processing and all that stuff.
All right. So, let's go ahead and initialize it. We don't really want to pass anything over here. So, let me remove that part.
And we're going to say model container for earthquake and model configuration is stored in memory false.
Earthquake client, we're just going to initialize it. Now, if you do have a factory or something which initializes the earthquake client based on the configuration, you can do that over here. That's fine.
Content view, okay, that's fine, too.
Model container, uh we're going to put the model container and pass in the container that we just initialized.
And on the task, we can add something.
Now, even the task over here is questionable and I'll talk about that.
All right?
Try await. So, this is where we can fire import earthquake service. import earthquakes using the container and using the earthquake client.
And then localized description.
Okay.
So, what's the deal with the task over here? Well, the task is going to get fired when your app actually launches and it is attached to the root view.
So, this means that the task is going to run.
Now, if the root view kind of goes away, then the task will automatically be canceled.
Now, it really depends like what we mean by going it away. Like, how can it go away? Well, you can kill the app and then it goes away. That's one thing.
You can move to a different screen, but since this is a root view, it will be in the navigation stack, so it will still be there.
If you have some sort of a condition is logged in, then show the task or else show login screen.
So, in those cases, it's uh our task is also going to get canceled because you're replacing the screen. We we don't really have these condition. I'm just showing you these things because there's so many different variations, right?
[snorts] If you are working on the app and the task is fired and then you move your app to the background because maybe you're taking a phone call or something, then the task will pause at that time.
And when you come back, it will resume.
All right?
Now, if you run your app right now, it will still work, right?
But this code right there, and in our case, this code might not be a big problem, but it's not really doing anything in the background. It's still tied up to the life cycle of the view, which in this case is the content view.
Right? And I've shown you the example uh that if you are switching between a content view and the login view, you know, these kind of things. It's one of those examples. Uh like if logged in, then you show this, else you show login view. So, in those cases, the content view is recreated again and again, right? So, in those cases, uh your task will get destroyed.
So, what should we do about this? I mean, this is going to work. It's not really going to um block your main thread because it's suspending over here, so it resumes on main thread and then it comes back when the job is done.
But it is still using the main actor because the task runs on the Swift UI view. Swift UI view runs on the main actor.
So, what can we do about that?
Well, one of the ways that we can do that is if we start using task.
detached.
Now, task.detached, as you can see, uh it is basically working. Uh it can work in the background and it is a detached task, right? It is a background task. So, I'm going to go ahead and pass something over here like background because that's the priority we want to give it.
Okay?
We're also putting this inside the initializer because if I put this code over here, then it's still tied up to the life cycle of the view because, you know, it's uh it's inside inside the task modifier.
So, what can we do in those cases?
>> [snorts] >> Like, we can actually uh move it out of the task modifier and into initializer.
And in the initializer, we can probably do all of this stuff.
So, let's go ahead and try to move move this part at least, first part.
There we go.
And we are going to go ahead and do this.
All right?
So, let's see what's going on over here now.
It is saying that we are capturing couple of different things over here.
Escaping closure, escaping closure mutating self parameter. So, that's the first thing we're talking about. And the reason is that the container as well as a client, you know, we are trying to uh capture the self over here because we don't really have any local variables identifying these things. So, one of the ways that you can do that is by saying let and by saying let over here also.
All right? So, once we create those two, container and the client, we can now assign this. Container equals to container local variable and client equals to uh earthquake client.
And the the things that we're passing over here, that will be the local variables.
Right? Like this one and this one.
All right. Let's go ahead and build it.
Okay. So, this will be truly detached task.
Now, this basically means that you know, it since it's completely detached, it's running in the background. If the view goes away, if you know, switch the views from login to content view, whatever you're doing, it's still running in the background and you know, downloading those things.
And I think the next step would be to just test it out. So, I'm going to go over here and delete the app that we were working on.
Again, there's so many different ways, right? So many different ways of doing the same exact thing.
Okay, so and there we go. So, we got the stuff.
And let me run it again.
There we go, instantly. All right. Now, again, keep in mind that I'm showing you this part the inside the import earthquake service already imported. Now, this may not be the thing that you want because this is actually saying that even if one earthquake is saved in the database, I'm not going to do anything after that.
Now, maybe that's something that you want. Maybe that's not something that you want. That's kind of like up to you.
All right. So, you can actually do it in many different ways. But, that's like one of the ways.
All right. Maybe you want it, maybe you don't want it. That's completely again.
So, this is where we have learned about uh how we can go about using our new model context. We can run it in the background.
And also task.detach, which actually runs our task that we're trying to do in the background.
Again, there's so many different ways of doing this. I'll probably go into more detail into the book that I'm writing on Swift data.
And you know, if you like all of this stuff, then check out my book also, Swift UI architecture patterns and practices for building, you know, scalable applications. Available as paperback on Amazon as well as an ebook on my own website. And the book is complete, so you can see all of these chapters.
Uh it took me probably 3 years, 3 and 1/2 years to research and then another year to write the book. So, hopefully you will enjoy the book. A lot of uh people are really, really enjoying the book and you know, buying it even as a gift for other developers, which is great.
So, definitely check it out. And once again, thank you so much for your continuous support. Thank you.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
So What's Odin Lang Even Good For
TechOverTea
131 views•2026-06-01











