How to use Core Data with @FetchRequest in SwiftUI | Continued Learning #14

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up everyone i'm nick welcome back this channel is called swiffle thinking where we cover all things swift and swift ui related and in this probably long-awaited video for some of you we are finally gonna jump in and tackle core data now in this video we're gonna look at using the fetch request and i would say this is kind of like the entry level the beginner version of using core data in your swift ui application and it to start we're actually going to create a new xcode project and we're going to check a little box that apple gives us that says use core data and by checking this box apple actually provides us with some template data to get started so what we're going to do is first run through that template data examine it and try to figure out what exactly it's all doing and then we're going to customize it so that we can actually use it in our own apps now i do want to mention before we get started that in the next video i'm going to run through pretty much the same process of adding core data into our app but not using a fetch request and actually using the mvvm architecture which i've used a bunch of times throughout this course so this video is showing you one way to use core data but the next video is also just as important for adding core data into your swift ui apps and i should mention for those of you who have no idea what core data is uh basically it is a database that is stored within the iphone and we can use it to save data to it and this data would persist between sessions so if a user closes the app and reopens the app this data will save if you follow my swift ui bootcamp we did a video on app storage and user defaults and this kind of works the same way except core data is much more for adding an entire database adding a ton of data rather than user defaults which should be used for small pieces of data all right i hope you're excited core data is super useful in production apps let's take a look alright guys i am back in xcode but for this one specific video we are actually going to create a new xcode project because when you create an xcode project there's an option to add core data into your app and apple actually gives us some template logic that we can use to get started with core data pretty quickly so let's go ahead and create a new project i'm going to click file new we're going to do a project this will be an app an ios app go ahead and click next let's call this core data boot camp uh it's okay if you don't have a team here you can leave that blank or none for now i'm just using my personal team organization identifier should just be com dot and then your organization or your team your company it's not very relevant for now because we're not going to put this into the app store the interface make sure it's swift ui the lifecycle swift ui app the language is swift and in this project we're going to use core data we're not going to host it in cloud kit so that can stay unchecked but make sure use core data is clicked here and when we click this apple is going to give us some of that template code to use chord data go ahead and click next find where you want to save it in your computer go ahead and click create all right and once we're in our project here let's first click resume on the canvas to make sure we're all connected and as you can see because we clicked core data there's a whole bunch of this template logic here that apple has already written and given us and there's also another file here which we're going to look in a minute called persistence which apple has given us so click resume and make sure we're all connected it might take a second to load because it's actually loading uh core data to load into the app right now all right and before we get coding we're going to take a look at some of this template code just to see what apple has given to us what some of this logic is actually doing so at the top here i'm just going to change my device to iphone 12 because it looks a little better so let's start at the beginning of our app here so we're going to go back into the chord data bootcamp app.swift file and in this file we can see the at main so this is where our app is starting and inside this file we are creating a persistence controller and if you follow my last couple videos we created some singleton classes and this right here is actually a singleton class so if we look at the persistence controller dot shared and i right click and jump to the definition we can see that static let's shared equals persistence controller so this is a singleton which we've been using so you should be used to this by now basically that means that this is one instance that we're going to use across our entire app i'm going to go back and it looks like we're getting a reference to this persistence controller right here and then we're putting this persistence controller into the environment now if you watch some of my other videos if you are familiar with the environment object this is kind of the same thing we're putting this whatever this is into the environment so that all of the views that are sub-views of this view will have access to whatever we're putting in the environment and it looks like we're putting in a view context so before we go to the content view let's take a look at what this persistence controller actually is so i'm going to jump to that i'm going to right click on the shared and jump to definition i could also just click on the persistence.swift file on the navigator on the left side and this is a struct called persistence controller we have a singleton so a single instance of it and it looks like this variable here is a static preview of the persistence controller that i'm guessing we're going to be using for the actual preview in our application below this it looks like we have another variable called container this is a type ns persistence container and then we have our init statement and this is where we actually are initializing a persistence controller and there's a parameter called in memory that's set to false by default unless we override it and it looks like we're first setting up this container by setting container equal to a new ns persistence container the name of this container is core data bootcamp and while we're looking at this the name coordinator bootcamp here is the exact same as the name of this other file coredatabootcamp.xc data model id and if you change if you named your project something else this probably says whatever your project name is and so does this so basically this container is referencing this file here then there's a little bit of logic here for if it's in the memory but we're not actually going to use that so i'm not going to worry about it and then there's a container.load persistent stores and this is basically the main function to load the data from the container so you can think of the container kind of as the database that's holding all of our data so here we're referencing where that all is stored and here we're loading all the content from that container so there's a little bit of logic here that says if there's an error cause a fatal error and fatal error is an automatic crash in your application and apple is doing this just in case we go to create this app and for some reason we can't find this persistent container because maybe we spelled this wrong well we're going to crash immediately so apple's just letting us know that if you set this up wrong we're going to cause a fatal error here and this is great for development purposes but i will say that if you're putting this into your actual application i would probably remove any fatal error because i would personally rather have the data not saving than the app actually crashing regardless we're going to keep it in for now because if we're setting up something wrong let's get it crashed so we know what we're doing wrong all right now that we see the persistence controller is basically creating the container loading the data into the container we can jump back into the core data app bootcamp app.swift so we have our controller which holds that container and then in the environment we're putting in the controller.container.viewcontext the viewcontext is actually going to be the data that's inside that container so if we jump into the content view we then have a very simple screen here we have a list and the list is a for each on items and if we look at the items it is actually this variable here so this variable is an add fetch request with sort descriptors this is basically just sorting all the data in this request so they're sorting it by timestamp and then with animation is just default and this items is of type bet results and is going to be a bunch of items so we're taking those items and we're looping through them and then says item at and then we get the timestamp and we can see that right here on the screen here's all of our items and then there's a toolbar which we can't actually see right now but if if we could see the toolbar and we are in a navigation view we would see this edit button and there should be a button to actually add an item as well so let's put our list into a navigation view just so we can start to see some of this toolbar so let's add a navigation view open the brackets and we're going to put the list inside so for our purposes because we're on an iphone we're actually not going to use the toolbar we're just going to use the navigation bar buttons so let's just go ahead and write navigation bar button now sorry navigation bar items leading and trailing the let's put these on separate lines the leading will be the edit button which we have right here and then the trailing will be this button so i'm just going to cut this button and just paste it into the view here let's get rid of this toolbar modifier and we should be able to see both of our buttons on the screen here let's take this list and give it a list style of plain list style just so we get back to our starting state and let's add a navigation title of maybe uh core data bootcamp all right very simple screen here we have all of our items that are just pre-loaded these are fake items right now we have the ability to add an item if we click this add item it automatically added one at the bottom and we can see here that the function is add item so in the add item it's doing it with animation it's creating a new item and then it this is a blank item right now and then it's going to give that item a time stamp which is the current date and then it's going to do this do statement which basically calls the context which remember we put into the environment at the beginning and it's just calling save on that context and if there's an error saving it's going to cause a fatal error and we're going to get a quick little crash when we have delete items it's almost the same logic this line of code is finding that data in the data array and then calling viewcontext.delete and after it's deleting an item it's just calling save again so if we swipe to delete on our preview we can actually delete these items and they're being saved in real time so if i were to close this app and reopen this app the core data would persist and it would save between sessions and this is all great that apple has given us this fetch request and the environment pre-loaded into our app but of course you know this model isn't exactly what we're looking for most of the time we're going to want to make our own models so let's go ahead and start changing this around to adapt for our template application right now so what we're going to do instead of just a list of items we're going to have a list of fruits and this will be a list of all the fruits that we want to save in our application so let's change the title to fruits let's get rid of the edit button because we're not even using it right now all right so let's first look at the item see what it is and then let's create a fruit so right now if we go into the core databootcamp.exe data model file we can see that we have an entity here and our entity is called item and it has a timestamp with a date so of course we want to create a new fruit entity instead of just an item and we're going to create a new entity instead of this item so let's go ahead and click add entity this entity we're going to call fruit entity i like to use the word entity just so that we know this is like a core data entity and if i click onto the fruit entity we should see that there is no attributes right now so we want to actually add some attributes and all of our fruits and all our fruits are going to have is basically a title so let's click the plus here let's add a name for the fruit and the name is going to be a string now if you had other attributes that you wanted to include in this data model so if you wanted to have booleans and more names or a subtitle you would go ahead and add all of these right here you would put your name and then whatever type you want it to be here now i'll note that you can't save images directly to chord data you could save binary data so you could convert an image into data you convert a color into data but you can't save a color or an image directly into core data when you're saving core data most of the time you're going to want to keep your data into the data types that are right here so doubles floats strings bools dates uids etc but i'm not going to use this one so let's press the minus sign and we're just going to have a name that is of type string while we're here we can also remove the item so let's just click on the item and click the delete button on your keyboard so the core data boot camp only has a fruit entity right now let's go back into the persistence.swift file let's take a look at this and this preview i forgot to mention is actually on the content view when you look at the preview of the contents it's referencing persistentcontroller.preview.container.viewcontext so we're going to go back into that persistence and when we look at this the persistence controller the logic is all fine but in this statement right here it's going for 0 to 10 it's creating a new item and the item it's putting into the context and then for each of those items it's going to give it a date and we just deleted the item from our context right so instead of adding an item here let's add a fruit entity it's not coming up on my app so i'm going to click command shift k to clean and rebuild let's try this again fruit entity and it is not working on my xcode project i've ran into this problem before sometimes the indexing just doesn't work when we update that data model so i'm going to actually just close out and quit xcode and then reopen this file real quick all right so i'm back in the file it is now finding that fruit entity i'm going to open the parentheses and go to the context we're going to add this to the view context which we found right here and let's call this new fruit and then we're just going to call new fruit dot name and we need to give it a name and i'm just going to add apple and then use the backslash open close parenthesis and let's just give it uh let's just give it an id based on this loop here so this will be let's call this x and let's just put x in here so our list should say apple one apple ii apple three apple four etc the rest of this looks good to me we'll go down here in the init this looks fine the container name is actually still core data bootcamp because we haven't changed this container here which is the file on the left if we created a new xc data model we would have had to change the name here and then we're just loading the persistent stores and this all looks good there's actually not much code we had a right here to update this for our new fruit so going back into core data at boot camp this should all be the same let's go back into the content view and now there are some things that we do need to update all right so first we're getting a an error on this fetch request that the fetch results it can't find item in scope and that's because of course we want fruits i'm going to create a new fetch request from scratch for you guys so let's go at fetch request open parentheses and we're going to look for the very simple one with entity and sort descriptors and this is first looking for what kind of entity we want to get from this fetch request so of course we want to get the fruit entity and we're going to call dot entity so now it knows what we want to get and then sort descriptors is how we want to sort this data right now we're not going to sort it at all so let's just keep this a blank array here and let's call this var fruits and this will be of type just like right here fetch results of fruit entity and let's go ahead and delete this first fetch request because we're not using it anymore let's take this fetch request which is called fruits put it into our for each this will be for each fruit let's change this text to say text and let's just give it the fruit dot name remember this should be like apple one apple two apple three otherwise with two question marks and we'll just put a blank string so if the fruit doesn't have a name we'll just leave a blank string and then we should be able to actually load this on the canvas and we can get all of our fruits coming in and remember we made the preview fruits just say apple with a number and let's go ahead and update our ad item function here so like before when we have the new item we're going to say let new fruit equals fruit entity let's give it the context which is the view context which we're pulling in again from the environment and then we're going to call new fruit dot name and we're going to set that equal to let's set this equal to orange we're going to update this in a second let's get rid of some of this old data and then i noticed that in the add item and the delete items both of these functions have this same do statement where we save the data so i'm just going to make that its own function so let's call private funk save items open close parenthesis open the brackets let's take this do statement let's just cut this paste it in here and we're going to call save items and again up here we'll delete this do statement and i'll call save items so very simply we create a new fruit we put it into the context we update that name and then we click save down here we need to delete the items and we're gonna find the item at this offset now this is probably a better approach to do it but it's a little complicated but it's a little complicated for beginner developers so we're just going to do this very simply we're going to say let index equals offsets dot first so this offset technically could have a bunch of indexes but when we select to delete we know that there's only going to be one index that we're worried about so we're going to look for the first indexed in this offset set and this is optional so let's say guard let index equals dot first else return then we'll say let fruit entity equals fruits and then we'll access that entity with the index and then we'll just call view context dot delete and we're going to pass in our fruit entity so i'll delete this logic here and very simply this is going to find our fruit delete it from the context and then we need to click save all right let's resume the canvas and we now have all of our apples let's click add item we get a new orange here and we can delete these items as well and if i were to run this on a simulator on an actual device i would be able to add items and then delete them and they would save forever because they're saving in core data now there's a couple things i want to do before we wrap up this video at the top right now it looks like these are not organized by anything and that's because we didn't add any sort descriptors so with this sort descriptors we can keep our data sorted however we want so i'm going to put this on a separate lines here and let's even put the var fruit on a separate line and let's add a descriptor in this array so i hold the option button and click on sort descriptors it is looking for an array of ns sort descriptor so let's add one ns sort descriptor open the parentheses i'm going to look for the one with a key path and ascending completion the key path is going to be backslash fruit entity dot name so we're going to sort by the name and let's just do ascending is true so our data should now be always organized by name and so we have apple zero at the top nine at the bottom and if i add an item the item is going to have the word orange so that should always be at the bottom so if i add items they will always go to the bottom and if we made this false and click to resume when we add items they will always be at the top because it is now organized is now sorted by name and it's descending so that looks awesome all right and now the last thing i want to do before we wrap up this video is actually show you this on a simulator and i don't like that we're adding the word orange every time i want to be able to add my own fruits so in this navigation view let's add a v-stack let's give it some spacing of 20 let's open the brackets let's take this list and list style let's cut it let's paste it inside the v stack and then above the list i'm going to add let's first add a text field open the parentheses let's use the string protocol and text the title of the text field will say add fruit here dot dot then we need a binding for this text so let's do at state var text field text of type string equals blank string for now the text let's bind it with the money sign text field text and let's try again to see if it pops up on our screen okay below it let's add a button open the parentheses let's use the action and label and i'm moving a little faster because we've done this so many times throughout this course let's do a little bit of formatting now so this button let's give it a font of headline let's give it a background color of color maybe we'll do a color literal we haven't done those in a while double click that color literal let's get a cool color going i'm going to open the crayons and maybe we'll use uh this blue looks kind of cool well let's do a darker blue cool let's give this a foreground color of white so white text let's give this a frame and i'm doing this before we add the background so frame of max width of infinity let's give it a frame with a width with a height of 55 looking better let's give it a dot corner radius of 10 and on the button let's just add some padding of horizontal cool let's edit the text field quickly let's give it a dot background let's give it a color color literal double-click color literal and i like to use this mercury color for text fields i think it's a nice off-white let's make it the same size i'm going to copy the frame and the width here put that before the background let's also give it a font of headline and let's give it a padding of horizontal let's also give it a corner radius sorry after the background and it's looking pretty good let's add a little bit of indentation here before the word add so before we add the frames let's just add a dot padding dot leading dot leading it has a little bit of padding right in there and this looks pretty good and now when we click this button we want to of course add fruits so in this button let's add let's click add item let's change this to submit this is looking pretty good we are not using this ad item on the top right anymore so let's get rid of that trailing bar items cool and lastly in our add item function instead of using the word orange let's just use the text that's in the text field so here we'll just put text field text and then after we use the text field text we want to reset it so down here after we click save let's just call text field text equals blank string now in my app here let's reload it just to make sure we are all connected and now that we have our app i think it is ready to actually test on a device so i'm going to make sure we're on the iphone 12 and let's run this on an actual simulator and see if it works all right when my app loads now we have a blank canvas and that's because when we're loading on the simulator we're not loading that preview like we've been doing with all those fake apples because in the content view when we're on when we're on the canvas we load that preview container but now we're loading the actual container in our app and it doesn't have anything saved yet which is why it's blank so let's go ahead and add some fruits let's do apple and it works orange and that works and remember we have ascending as false so i actually want to make it ascending so let's put that as true let's run the simulator one more time and you'll notice that when we restarted our app it now saved this data in core data and then pulled it back from core data so these will save forever and this is very efficient if you actually want to put an app into the app store this is a great place to save a ton of data so we can add watermelon when we add this the w should be at the end of the list and if we add another one maybe banana you'll see that it goes right in alphabetical order we can of course also delete items and if we delete the items they will persist so i can totally shut down my app here and then restart it and it will load the exact same data all right and the very last thing i want to show you guys which i just realized is that some of you're going to ask how to update items so we have adding items we have deleting items we are getting items by through the fetch request but we are not updating items anywhere so let's create a quick little function let's put it after the add items let's create a private funk uh update item open close parenthesis open the brackets and we want to do whatever we're going to do with animation let's open the brackets basically the logic is exactly like we have in the delete items where we first need to get the entity and then we need to call something on it so here we're getting the entity and then we call delete and then we save it and when we add item we are creating an entity we are adding it to the context and then we are saving it and here we are going to get the entity and then save it so at the bottom here let's just put save items to make sure we don't forget that and then we need to get the entity and when we swipe to delete items we because we're using the swipe to delete it's it automatically gives us the offsets right that's if we go back up here this on delete action gives us those offsets but when we go to update we're actually just going to add a tap gesture onto the text so i'm going to use the dot on tap gesture and then from on tap gesture we're just going to call update item and we're going to pass in the fruit that we're tapping on so this fruit is an entity already so when we called delete items we needed to take the offset and then find the entity from the offset but since we're already tapping on it we already have the entity so i'm going to add fruit of type fruit entity in the tap gesture we'll call update item and we'll just pass in the fruit directly so we already have the entity and then we can just update the entity directly so we'll say let current name equals fruit.name and this is optional so we'll just say two question marks and then we'll give it a blank string so if there's no name which we know there is a name but if there's no name it would be a blank string then we'll say let new name equals the current name plus an exclamation point and then we'll just say fruit.name and we'll set it equal to the new name so when we want to update an item all we need to do is get the entity itself update one of the variables in the entity and then save it back down so it's really that simple and if i rerun the app one more time if i click on the orange it should now update the entity and we are saving and this should persist so if i close down the app and reopened it because it's in core data it will save now of course in your actual app you're probably not going to just add an exclamation point you're going to add some ui to actually update the items maybe change the title maybe change a number of how many oranges or watermelons you want but the basic logic for updating is exactly this get the entity update a variable and hit save so to run through this one final time to add an item all we need to do is create an entity put it in the context and this will be a blank entity so we just need to update all the variables with the data and then click save when we update we just need to get the entity and then update whatever variables we want and then click save and when we delete we just need to find the entity and then delete it from the context and then click save and our save is very simple is just a do view context dot save all right guys i hope you're feeling a little more comfortable with core data we now have the ability to add items we have the ability to delete items we can update items and we're doing it all with this handy fetch request and just to remind you the reason we can do this fetch request at all is because in the app.swift file we are getting the core data view context which we are then putting into the environment and then we're pulling the view context from the environment so that we can use it and we can perform the fetch request which then gets our fruit entities and then at the bottom we have all of our functions to add update delete and save now this is great of course and it's a great starting point if you've never used core data before this fetch request makes getting that data into your view very fast and very easy uh so it's great for beginners but if you followed my courses if you're familiar with mvvm architecture you're probably well aware that a lot of the time when you're making apps you want to separate the logic in your apps so that each file or each layer has a specific purpose and right now in our view as you can see we have a lot of logic because we have the logic for the data coming in in this fetch request then we have the logic for the actual ui in the view here and then we have more functions for the actual data so in mvvm architecture we would actually extract all of these functions here and we would take even the fetch request and we would go and put it in another file so that the logic that remains in the view is specifically related to the view which would be the actual ui components and the logic in the class or the view model is specific to the data source and that's where we would do all of our data updating downloading appending etc if that's something you're interested in i highly recommend you to stick around for the next video because in the next video we are going to do essentially the same thing that we just did here but instead of using the fetch request we are going to implement core data with mvvm architecture because i do believe that that is a little more realistic for production applications all right guys that was a lot of me talking i hope you followed that and i hope you're excited for the next video as always i'm nick this is swiffle thinking and i'll see you in the next video
Info
Channel: Swiftful Thinking
Views: 4,118
Rating: undefined out of 5
Keywords: Learn SwiftUI, SwiftUI Core Data, SwiftUI CoreData, SwiftUI what is core data, SwiftUI how to use Core data, SwiftUI fetchrequest, SwiftUI FetchRequest, SwiftUI Fetch Request, SwiftUI @FetchRequest, How to use @FetchRequest, How to use @FetchRequest SwiftUI, How to add core data into SwiftUI app, How to add Core Data, Add core data into SwiftUI, Add core data to SwiftUI, add Fetch request in SwiftUI, add @FetchRequest SwiftUI, @FetchRequest, @FetchRequest SwiftUI
Id: nalfX8yP0wc
Channel Id: undefined
Length: 36min 34sec (2194 seconds)
Published: Wed Apr 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.