CoreData helps you manage and store data in
your iOS Apps, but it can be hard to implement. Well not anymore. Alex here from rebeloper.com and
today I will teach you how to use CoreData in SwiftUI. So if you are interested hit that
SUBSCRIBE button and open up Xcode and let's dive into learning CoreData in SwiftUI.
So let's learn how to use CoreData in SwiftUI. We are going to start off from scratch.
So we are going to create a brand new Xcode project. But before I dive into this let me just remind
you about rebeloper.com/mentoring. 60 minutes of one-on-one Zoom call with me. If you have a bug
or you want to learn SwiftUI or even UIKit go ahead and check it out rebeloper.com/mentoring
where you will be able to meet me on a one hour, 60 minutes Zoom call. We are going to start off
with a brand new Xcode project and I'm going to go ahead and create one. Let me just resize
this so you can see it a little bit better. There we go and let's select iOS and App.
Let's click on next here and I will name this... And you can just check this use CoreData but I will not.
I will start off from scratch building out all the CoreData related stuff so maybe if
you are having an existing SwiftUI project you can use this tutorial, okay. Make sure that you have
SwiftUI as the interface and SwiftUI app life cycle. Let's click on next and let's just
add it right over here under videos, there we go. And let's create a new folder. I'll just name this
Code and finally let's create it right over here. Okay! So yeah I won't to use Canvas.
So I'm just going to remove that. First things first we want to create a CoreData Stack and I'm just
going to name this a Stash. So what you want to do is just go ahead and right click on here.
Let's create a new file and let's just scroll all the way down and you will see that we have a
CoreData model right over here. Let's click on next and let's name this Stash. You could just name
it whatever you'd like, I'm usually calling it stash because I'm stashing away all that
data, okay. Let's create that and there we go. We have our data model right over there.
Let's move this right into that SwiftUI CoreData group and I'm going to create two entities. One is for the
item and the other one is for categories because we are going to link them together. So let's tap
on this plus button. Let's name this Entity Item. Okay and this item should have one attribute
and that is name and it should be a string value, okay. Let's create the second one
and let that entity be named category. Okay and that category will have also a name.
Now you will be able to add in here much more for the sake of this simple tutorial this is enough.
Now I want to have relationships between them. So items may be associated to categories
and also categories may have a lot of items. So what you want to do here is go, let me
just have here much more space. So just go under relationships. You will have
a plus button right over here and we are inside the category
so I will name this relationship to item. Okay and destination is item and let's
just go into item do the same thing. Now I will name this two category and this
is destination is category and set this the inverse to item and let's just go right over here,
as you can see the inverse has already been added really nice. So this is our default data model.
What we are going to do next is just create a persistence controller that we are going to use
throughout the app. It will be having a shared property so you will be able to access
it throughout your app. So let's create that. Let's just go right over here. Let's create a new file.
It will be a swift file and let's name this Persistence Controller, okay. So first things
first we want to import CoreData here. Right! And this will be a struct. Let's have this copied
out and paste it in as the name and first of all let's create a shared static let here.
So we can use it as a singleton. So static let shared equals persistence, let's hit Command + B
so we have that auto completion. Persistence Controller and that's it.
Okay! So what we want to have here first is actually a container. So let's see.
Let's hit Command + B so I get rid of that error. Okay! Build has succeeded. Really nice!
Let's create our container and NSPersistence, NSPersistenceContainer, there we go.
So we got our container, what we want to do is just initialize it when we are creating our Persistence Controller.
So let's create an init right over here. we don't have any parameters but we're just going
to use container equals NSPersistenceContainer with a name and go ahead and add in the name that
you created for your CoreData Model, mine is Stash. Okay! Once you have that initialized the container
you want to load the persistent stores. So container dot load persistent stores with the
completion. We might get back a description but we don't really care about that or an error.
Now if there is any error we just simply want to crash the app. You don't want to use the app if the
persistence stores weren't loaded. So if let error equals error. Then we just go
fatal error with a message and let's call it like error and let's
add in here our errors localized description. Okay and that's it for our initializer.
Now we have our persistence container created and loaded the persistent stores. Now what we want to do in this
persistence controller to be accessible we want to have a save and the delete function, okay.
So let's do that. Let's start off with the save. So func save and on the save, yes we might encounter
an error but we might not worry about it but let's just create a completion
here with the default completion. So completion. So yeah with the default completion
because we might not want to use it. @escaping and we might complete, let me
just add in here the full completion and this will be, this is kind of the default value.
Let's just add it that in there. So this is our default value and we are going to get back an
optional error. So we will get back an error. I think we are missing some things.
Let's see escaping. Yes! I just added that colon and it doesn't have to be there, okay.
So we will be completing with an error if we find any errors or we are going to complete with nil if
everything worked okay. So let's grab our context... ...equals container container dot managed
view context, yes. It's view context and if context has changes. So if this context has changes that
weren't already saved. So with this if statement we are kind of ruling out that we are saving over and
over again even if we don't have any changes. Then we are going to go and try to save our context
with a do catch statement. We are going to go try context dot save, okay. As you saw it will throw
an error and on the catch we are going to complete. So completion and the error, okay.
If everything went okay we just go and complete with nil as I already told you, okay. This is fine.
So now we have our save let's create our delete function. So func delete, so we will use these later on in our
project throughout. So we are going to delete an object and that will be an NSManagedObject,
there we go and we are also going to complete like we did with the save.
So let me just copy that out and paste it in there. Okay! So how do we do that? We again we just grab
our context and that is from the container dot viewContext and we just go context
delete our item, our object basically. Okay! So once we delete on the object
on the context we still have to save our view context. So we just go save and use
the one with the completion and just go completion because the delete completion is the same as the
save completion, okay. Real nice! So now we have this kind of helper file persistence controller let's
add it to our project. So first of all we want to add this into our view hierarchy and we are
going to start off on the SwiftUI CoreData App file so right over here. We are going to create
our persistence controller right over here. So let, let's just have this as a new line.
Let persistence controller equals persistence controller dot shared, okay.
So now that we have that we want to add it as the managed object environment. Now I don't know
if you have learned or heard about environments. If you add an environment into your content
views or any of the views basically you will be able to access it throughout all of your other views.
So let's just go and grab environment. Now the key path will be backwards slash dot managed
object context and this will be our persistence controller. So this is just a controller.
So we want to grab its container and the view context. Okay! So that's our managed object content in the
injected as an environment into the content view. Okay! This is great! So we are going to save
and delete stuff but it's a good practice to save the managed object context when the app
goes into background. So how do we do that? Usually we went into the scene delegate and there
we had when we went into the background so that delegate method. Now with this new SwiftUI app
structure we are going to get the scene phase and there we're just going to save our contacts in
the background. So let me just do this, first of all we want to grab the scene face environment.
So @environment and backward slash dot scene phase. Okay and that will be a variable called
scene phase, okay. So now that we got our scene phase we want to listen to
it and we are going to listen to it on an onChange of scene phase.
So dot onChange of scene, scene face, there we go.
Make sure that this is on the window group. We are going to perform equatable
is the new scene phase, okay phase and let's just switch through
all of those. So switch new scene phase and let's just wait Xcode complain
and add the values right over there and as you can see we have background inactive, active and we are
going to go and just print out some stuff for now. Oka! Let's just go with all of these
and scene is in active. Scene is active and on the default well that's just the future
proofing this switch statement. We want to add, well actually we want to save on the background.
So we just go and select our persistence controller and go ahead and save. I'm just going to
use the one without the completion. I don't really care I'm just going to save right over here, okay.
So that is one really important part so you save your persistence container on the background when
we the app goes into background, okay. So now it's time to take a look at the content view. So on the
content view we are going to create kind of two buttons because we are going to create a create
a new item or create a category and we are going to list those items in actually a list.
So let's start by creating our views right over here. So first thing we are going to do is
just create a VStack and inside that VStack we are going to add in a button.
So let's see, a button right over here, okay. Let's just use the one with the action and label
and on the text let's just add category. Okay! Let's do the same for our item.
So let's just add it right below it add item. Okay! So whenever we are going to tap on add item
we want to check if there are any categories. So for that we are going to add in here an alert.
So let's see, yeah let's just go ahead and leave these as are. Let's just worry about the
list for now. For the list will be right over here and a list I'm going to use a forEach
view, but for the forEach view I do need the items. So let's scroll all the way up and let's create
a fetch request for those items right over here. We do need a fetch request but the fetch request
will also need the manage object context. So let's just import that environment.
@environment and backward slash managed object context, there we go. That will be a
variable called again managed object context. Okay! So that's our managed object contacts.
Next we are going to create that fetch request. So we are actually going to use again a property wrapper for
those items and let's just go ahead and type out @fetchRequest, there we go and if you go open
up parentheses we will see that we have a few variables here with an entity, sort descriptor, predicate,
animation. I'm just going to use the one with the sort descriptors and predicate. I don't really
care about the animation. Let's see if we have, no we don't have, yeah so let's just use this one.
Animation as you can see so predicate animation could be optional. So I'm just going to
omit animation, okay. So the entity. What is the actual entity? Well we are going to fetch
some items. That is important that you created that object on your CoreData Model. So item dots
entity, okay. That's our entity. What are the sort descriptors? Well how should CoreData give us back
this array of items and I think we should just go ahead and order them by name. So here you can have
an array of sort descriptors. You could just have more like sort them by name or caption or
sub title or whatever you'd like. I'm just going to add in here one. So this will be an NSSortDescriptor,
there we go and that sort descriptor should have a key path and let's just go with
ascending. So the key path will be backward slash item dot name. So we are interested in the name and
ascending let's set this to true, okay. Now for the predicate yeah the predicate is well actually we
don't really need a predicate right over here but I'm going to type it out for you.
So let's create an NSPredicate and let's have one with the format and arguments, okay. So the format
should be like let's just search for the name and that will be equals to and the percentage
and at (%@). So that means that we the name should be equal to the argument that we are adding it here.
So it should be equals to something, let's just see we are going to save some clothes and the item
will be a shirt. So let's just go ahead and add shirt. So only the shirts will appear.
You know I do understand that this is not kind of what we actually want to do right here but you know
how to use our predicates and I think we need to not have these arguments right over here.
Yes! Animation we can just safely remove that, go ahead and check it out just add an animation how these
entities will be presented. And finally we want to get var items and this will be a fetched
result of type items. So fetched result. Fetched result of item, okay.
So this was quite long but yeah you added the entity. Let's just add
that right over here, the sort descriptors, the predicate and then you just named it as items.
Maybe let's just move all of these down here and this one right over here, okay. What you want
to do just select all of them and hit Ctrl +I so it gets this nice indentation, okay.
So we got our items. Let's just add them into our list because yeah that is what we actually wanted.
Now we are going to use a forEach view and we are going to go through all of the items, okay.
The id will be self so all of them will be identical and right over here we are going to add item in.
So we are going to get back an item, okay. So now that we got our item we just need to just
make them visible I'm just going to use a text and I'm going to set out the item names. Now if the
item name doesn't exist then I'm going to print out unknown. So let's just interpolate that item
dot name. If this doesn't exist let's just go with unknown, yes we do. Yes I think.
Yes I want to add that right over here, correct. Okay! Unknown and yeah basically that is it.
Let's see so this is how we add our items. So let's tap on the button and let's add one of our items.
So let's create on the button, well first of all I think that we should actually create
a category first so we can tie it to the item. Okay! So again let's create a fetch request right
over there on the categories. So let me just copy this out and have this as category, okay.
Now category will be our key path and then the predicate. Well I don't think we do
need a predicate right over here, I'm just going to remove this and let's name these categories, okay.
So now we have access to all of those categories. Okay! So now let's just see if there are any
categories. If there are categories then we are going to go ahead and present an action
sheet that where we'll be able to select the categories that we already have in there, okay.
So if categories dot count equals zero then we are going to show an alert. Else we are going
to show an action sheet. So let's just create those state variables so we can use them when
creating the alert and the action sheet and let's just add them right over here.
So private state and is action sheet presented false by default and again a new straight
private variable is alert presented. That will be false, okay. So what we want to do is
if the categories count equals to zero we want to present our alert. So isAlertPresented.toggle() and
otherwise is action sheet presented we are going to toggle that. So let's add in those two.
Let's start off with the action sheet. I'm going to add them right on this button. So dot action sheet is
presented and the dollar is action sheet presented for the binding and the content, well the content
will actually be an action sheet but we do want to have, I think i needed to add a dot here. What we
would do want to add all of the buttons. So let's create the buttons first and then we are going to
add them to the action sheet and return the action sheet right over here, okay. So I believe I didn't
have that auto completed correctly. So let me just do that again. So action sheet is presented dollar
is action sheet presented, okay. So everything seems to be okay. So first of all let's create an
array of buttons because there might be a lot more than one categories. So that will be an action
sheet, there we go. Action sheet the dot button and let it be an empty array, okay. So we go through
all of the categories. So categories forEach and we are getting our category right over here.
So for all of those we want to create a button and that will be actually an action sheet. Action sheet button dot button and let's just go with the default because
there might be more. You can't have more cancel buttons. So that's why I'm choosing this and I'm
going to go with the default label and action. The label will be our categories name.
So let's create a text right over here and category dot name, okay. That should fix itself
and if that doesn't exist it should go unknown. Okay! And what about the action? Well this is where
we want to go ahead and create an item for that category. Before we do that let me just add a
new console button here. So buttons dot append console dot console, okay. And finally let's
just return an action sheet so we don't don't have that error all already in there. So action sheet
and we are going to use the one with the title and buttons. So the title will be again a new text, okay.
Please select the category. Message could be nil, so I'm going to go with nil and buttons,
there we go. So now we won't have any errors. So this is whenever we tapped on the item,
what's going on here, action sheet, title, buttons. Oh! I added the return inside the completion
so that is not what we want. We want to add it right over here also the appending
of the console button right over here. Okay! So what we want to do here is create
a new item. So let item equals and item with a context and that context will be
our managed context that we just created and we can just set the item dot name.
Let's just have it as shirt for now. Yeah you can just go ahead and move this forward. So you can add
multiple types of items but currently it's just going to create one shirt and then we are going
to tie this to this category. So item two category equals category. So this is how we kind of link
them together. Also now that we have the name and the two categories set we can just simply save.
So persistence controller dot shared and just go with save. I'm not going to take care of I don't
worry about the completion. I'm just going to go with save, okay. So after we got our button we just
want to go and append that. So buttons dot append the button right over there. Nice! So finally what
we want to do is as you can see if the categories there are no categories we want to present an
alert. So let's do that. Let's create an alert right over here with the is presented. We just bind it
to is alert presented and the content will be an alert, there we go. Alert with the title, yes title
message and dismiss button. Well I'm not going to care about dismiss, sorry about the message.
Let's just go with the title and that will be a text and let's just go "Please add category", okay.
And message nil and dismiss button, let's just go with a dot cancel button
with a label of okay. So text okay. So yeah, so now that we have all the categories
also set up we might want to add the categories right over here. So let's just create the
item dot to category, there we go dot name. Okay! Oh sorry name and that to category
is an optional. So let's just have that right over there and if this doesn't exist
then again let's just go with unknown. Okay! Yes, so now we can just simply build and
run let's select one of our iPhone 12 simulators. Let's build and run and now we will be able to
add a new category and add a category an item onto that category and after that we are finally
going to learn how to delete. That is really really straightforward. So if i tap on add item you will
see that it says "Please add a category", okay. Let's add a category, so yeah hit just save that under
the hood and now we can just tap on add item. Well it doesn't seem to save it.
Yes, we didn't save it actually. So let's go all the way up right over here when we are adding
a category and yeah let's create a category. It will be the kind of the same as we did
with the items. So let category equals category. There we go and let's grab our
context managed object context and let's add a name for our category.
Name, let's go with clothes, okay and then persistencecontroller.shared.save, okay and that
should be it for our category, okay. Let's build and run and see how this looks like, okay.
So let's tap on add item, okay. Please add a category. Let's add a category that should have saved that because we
didn't have the code actually and now let's add item you can see that it fetched the clothes.
Let's select clothes and there we go we have a shirt under the clothes, okay. So we should be able to
delete this. So how do we do this? Well we want to add a delete function on the list itself.
So let me just scroll all the way down and on the forEach we could just add an on delete but let me just
create our function first for it. So func remove item and we want to remove an
item at an offsets and that will be our index set, okay.
Deleting is pretty straightforward first of all we want to know that we want to loop through all
of the indexes on that offset. So for index in offsets. Let's grab our item ,equal items
add that index, there we go and then we just go persistencecontroller.shared.delete that
object and the object will be our item. Items and categories are NSManageObjects, okay.
So what we want to go is just go onDelete and don't you autocomplete here because it will just
add perform. What we want to do is just type out perform and there we go. So that is it.
So remove item at offsets and let's just hit Command + R and we should be able to swipe,
there we go and if we just hit delete it will remove that item. Really, really nice. Let's add an item
again clothes. There we go and we can just swipe all the way out and it will delete it. So that is
it for CoreData in SwiftUI. Now you know how to save and delete and set up your CoreData Model
and use all of those with a fetch request. So you can fetch all of your entities, items or categories
and you can also add sort descriptors predicates. Now if you are interested in setting up a
fetch request limit then you want to not use the built-in fetch request, you want to create just
a simple fast request and then on the initializer you want to add to that request a fetch limit, okay.
That's it for CoreData and SwiftUI. Now if you did enjoy this teaching style go ahead and
check out DEV_FACTORY and that is a 60 minutes one-on-one Zoom call with me. If you have any bugs
in your code or if you do want to learn SwiftUI go ahead and check out rebeloper.com/mentoring
where I will teach you well whatever you want bug fixes, SwiftUI, I'm here for you.
As of SwiftUI you can implement CoreData relatively simple as you already saw. So I hope you will do so in
your next project. Now if you did like this video go ahead and give it a thumbs up and while you
are at it make sure to hit that notification bell to get notified of new videos as they do come
out for example take a look at these videos. I talk a lot about SwiftUI, Swift in general
and as usual I will see you in the next one.