How to use Core Data with MVVM Architecture in SwiftUI | Continued Learning #15

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] welcome back everyone i'm nick this channel is swiffle thinking where we cover all things swift and swift ui related and in this very fun video we're going to add core data to our app using mvvm architecture now if you're not familiar with mvvm it stands for model view view model and basically the idea is to separate the files in our app so that the code for the view which is the ui is separate from the code for the view model which should handle all of the data and in the last video in this series i covered adding core data to your swift ui app using a fetch request and while that is great the problem with that is that the fetch request requires us to add all of the logic four core data into our view and as you saw on the last video it works but it does start to add a lot of extra code into the view that could get confusing and not necessarily scalable so in this video we're going to look at an alternative approach by adding the core data into the view model and i think this is something that's a little more practical for production applications and if you've never used core data before uh basically it is a local database on the iphone that we can use to save information to and this data will persist between sessions so if we close the app and we open the app the data still saves all right that's enough of me talking let's jump into xcode and i want to point out that i'm going to use the same project that i used for the rest of the course excluding the last video so i'm going to jump back into our normal xcode project and we're going to create a new file and get coding okay welcome back everyone i am back in our original xcode project so the last video we created a new project but i'm actually back in our original project where we have all the files from this course and for this video i'm going to right click the navigator and just create a new file this will be a swift ui view we're going to call it core data boot camp go ahead and click create once you're inside let's click resume on the canvas i'm going to leave the navigator open for a second because we are going to use it now i do want to mention if you're just joining that in the last video in the series i covered core data by using a fetch request and i view the press request kind of as the beginner introductory way to get core data into your app because it does make it really easy to get the data into the view but in a actual production app it's kind of not realistic to put all that logic into the view so instead of putting all that logic into the view we can extract it into a view model and this drives us into mvvm architecture so real quick for anyone who's never done mvvm before and if you haven't i recommend checking out the swift ui to-do list which is the playlist on my youtube channel where we actually make a beginner level mvvm app but real simple there's three layers we have the view which is the ui we have the model which is sort of like a data point and then we have the view model and this i would say manages the data for a view so behind the view is actually a view model that holds all the data and that data is going to be a bunch of models all right let's get started before i bore you guys because i know i've covered all of this before let's create a class we're going to call it core data view model let's make it conform to observable object and go ahead and open the brackets we're making it conform to observable objects so that we can observe it from our view so let's initialize a new one in our view we'll create an at state object var we'll call it vm for view model and we'll set it equal to a new core data view model open close parentheses and let's start setting up our core data so first we need to import core data at the top so if you watch my last video most of the logic right now is going to be very similar because the template logic that apple gave us is basically what we need to recreate here so inside this we're going to create an init open close the parentheses open the brackets and the first thing we need to set up is our container so we'll say let container of type ns persistent container so now we need to set this up in our knit and if we don't xcode actually gives us an error returning from initializer without initializing all stored properties basically means we're finishing our knit without setting up the container so let's set up let's call container equals a new ns persistent container open the parentheses and we're going to use the completion with the name now we haven't made the container yet so let's just leave the name as a blank string for a second and then after we get our container we need to call container dot load persistent stores this just loads basically all the data from the container let's click enter on the handler i'll make this a little bigger for a second this is going to return ns persistence store description and an error let's call this description and let's call this error and we're not going to really use either of these but if there's an error let's print it out so that we get a little indication that maybe there's a problem loading the stores so we'll say if let error equals error and we will print error loading core data and then let's just do the backslash open close parenthesis and print out the error so if there's an error here we can just print it out and that's all logic we need to load up core data that's so simple and so short it's awesome but of course we didn't set up this container yet so let's do that now and to do that we're going to right click the navigator create a new file so if we scroll down there's a core data section and in the core data section we're going to click on the data model and click next and then we can call we can call it whatever we want and this is going to be the name of our container so i'm going to call this fruits container fruits container let's click create and you can see here that the fruits container it says fruits container over here on the left and then we're in this container and all we need to do here is add our data model so basically it's going to be one entity so we're going to add an entity and we can name the entity we're going to name this we're going to name this fruit entity and click enter you don't need to include the word entity at the end but i like to so just so that we know this is a core data entity and in this model we can give it a bunch of attributes just like we do any other model in our app and we're going to give it one very simple attribute so let's press add item we're going to say name and we're going to set the name to be a string now again if you want to save a bunch of data for one entity so if a fruit had some other attributes you could add them here by pressing the plus setting up all of the types and as i mentioned in the last video in chord data i would definitely try to stick to saving the types that you see here so dates boolean strings floats doubles you'll notice here that it does not say images because you cannot save an image or an audio file or a video file directly to core data now you could convert an image into binary data and then save it into core data but that's not necessarily the recommended approach so i don't want to tell you guys to do that i'm going to cover saving images in a future video in this course but i would recommend trying to stick to the types that you do see here i'm just going to keep the name with a string so for this attribute i'm just going to remove it with the minus sign here so a fruit entity and our fruit entity only has a name and it's a string so now that we have this let's just jump back into the core data boot camp we have our ns persistence container and the name we can see it right here is the fruits container so if you create a different data model the name would be right here a dot xc data model so let's say fruits container make sure this is exactly as it is here word for word and it might even be a case sensitive so just make sure you have this string correct and right now if we don't get an error let's just say else and let's print successfully loaded core data so with this right now we should be able to figure out if we at least set up core data correctly or not so let's take the core data boot camp let's put it into let's go into the app.swift file let's make this coordinated bootcamp the first view in our app and let's run it on a simulator to see what prints out all right i loaded my screen and i got the printouts of the console successfully loaded core data so if you have so if you're following along and you got this error loading core data chances are you spelled the name wrong here this ns persistence container name needs to match the container exactly so we got this container set up we can actually create a fetch request to get the data from the container so underneath this init and i'll zoom out here because i see this a little big let's create a funk we'll call it fetch fruits open close parenthesis open the brackets and in the last video we used at fetch request and now because we're not in a view we can't use that at fetch request property wrapper but we can still create a fetch request so we'll say let request equals ns fetch request open the parentheses and we're going to go down to the entity name and the entity name needs to be exactly what we set up in our container so if i open the container my entity name is fruit entity so make sure you're doing this exactly as well make sure it's exactly letter for letter and it might even be case sensitive i'm not sure so mine is fruit entity and we're going to get one more error that the generic parameter result type could not be inferred now i haven't covered generics in my courses i'm actually doing that later in this series but for now basically this nhs request wants to know what kind of entity this entity is what should we expect so all we need to do is use the less than sign and the greater than sign and inside these two signs we will add the fruit entity and my xcode cannot find fruit entity in scope i'm just going to x out xcode and reload it and i think that will fix it we'll find out in a second so i literally just reloaded xcode and now it is green so it found the fruit entity sometimes when you're adding these core data entities the indexing just gets a little messed up just a reload xcode and it should work now that we have our request we can actually call it so we'll say container which is our container that we created up here we will say dot view context dot fetch and we're gonna use the result that throws and obviously the request of type ns fetch request is going to be our request that we set up you saw that this call can throw so we need to mark it with try so we'll say do we'll put all of our do statements in here and then we'll say catch let error open the brackets and in this catch we'll just say print error fetching and then i will do a backslash open close parenthesis and then print out the error and i kind of am doing this on purpose because xcode gives us all these really cool hints on how to write our code if we get lost if we get stuck and something's not working so now i did my doing cash statement and i'm getting a error message here that the call can throw but is not marked with try so all we need to do is add the word try in front of it and i can even just click this fix to make it say try and that's awesome and even farther now xcode is telling us the result of this call this line is not being used and that's because we haven't saved it anywhere so where we're going to put it when we actually fetch this data so at the top of our view model let's create an at published at published var let's call it saved entities and this will be of type and will mean array of fruit entity and we'll set it equal to a blank array for now and we're just going to say saved entities equals try.container fetch all right so it's going to create the fetch request try to fetch from the container and then the result will be stored in saved entities so after the load persistent stores we will call fetch fruits and i think it should work i don't think we need to put it into the closure here uh we'll find out in a second anyway i'm going to delete this else because we already know that it's it's set up successfully we were functioning to fetch but we haven't actually added any fruits so let's create another funk add fruit open close parenthesis open the brackets when we add a fruit we need the name so we'll say text of type string and just like in the last video when you add something you basically just need to create a fruit entity give it some data and then save so we'll say let new fruit equals fruit entity open the parentheses i'm going to use the context here and we're going to enter it into the container dot view context it's the same container that we've been using this whole time now this is a blank fruit and we need to add some data so we'll say new fruit dot name which is the variable we gave it and we'll set it equal to the text that we're passing into this function and then we very simply need to call save so i'm going to create a function for the save because we're going to reuse it we'll say funk save data open close parentheses open the brackets and this will be very simple we'll call container dot view context dot save and just like before this call can throw and it's not marked with try so we can add the do open the brackets put our calls inside we'll mark it with try and we'll catch the errors and we'll say let error and we will print error saving backslash open close parentheses and we'll print out the error here and if we do save this successfully in the last video we used an at fetch request which every time the data was saved it automatically updated on our view but now our data on our view is actually going to be linked to this published variable so every time we click save we need to re-update this published variable and the simplest way to do it right now is to just call fetch fruits again because when we call fetch fruits it creates that fetch request and then it sets our saved entities equal to that whole request so if we added a fruit and then called this again the new fetch request would include that new fruit so after we click save here we'll just call fetch fruits and then of course at the end of ad fruit we'll call save data all right that was a lot of code let's get this let's get the ui set up and then actually test this out so i'm down in our view here i'm going to open up the canvas quick so let's create a navigation view inside we'll add a v stack with some spacing of 20 i'm gonna move faster here because if you've been following my courses this should all be super familiar to you let's add a navigation title let's call it fruits and let's the first thing in this v stack let's add a text field open the parentheses let's use the string and binding and the title we're going to call it add fruit here dot dot dot and the text we need to bind it to something so let's create an at state var text field text of type string equals a blank string and we will bind it with the money sign text field text let's give this a dot font of headline let's give it a dot background of color and let's make it a color literal and i'm going to double click on this white click on the other and we're going to use the mercury which i think is a good color for text fields before the background let's give it a dot frame with a height of 55 let's give it a corner radius of 10 and let's click try again and see what it looks like so far all right so i got my fruits down here um let's add maybe some padding dot horizontal and for now i'm just going to add a spacer to push it up all right before the background color in the frame i'm just going to add padding dot leading to get the little indentation right here cool and below that let's add a button we will add a action and label and if you watch the last video you could just copy the view from the last video i'm just doing this again for people who are just joining let's make the button text font dot headline let's give it a foreground color of white and let's give it a background color let's do another color literal because i love color literals let's double click on the color literal let's use a new color maybe maybe this strawberry let's go pink i'm feeling like pink today let's give this a dot frame up height of 55 and a frame with a max width of infinity all right let's give it a corner radius of 10 to match the text field and let's finally add that padding horizontal onto this button so that it matches beautiful when we click this button we want to take the text field text and then call add fruit which we made before so in the button we're going to say vm dot ad fruit remember vm is the view model that we set up up here and we will pass in the text field text now this text field text starts as a blank string so i just want to make sure that it has at least one character so we're going to say guard text field text dot is empty else return and we're going to say when we're going to use the exclamation point to make sure that it is not empty so we're going to say this is is empty and this is not so make sure it's not empty and if it's not empty we will add the text field text and then we will set the text field text equal to a blank string so it reverts back okay and then and then lastly let's just add a list underneath this button so i'm going to get rid of the spacer i'm going to add a list open the brackets and then we're going to add a for each statement into this list i'm going to open the brackets and we're going to use this first completion here with just data the data is going to be the vm or view model dot saved entities this is the array that we made before we're going to click enter on the content and this will just be for each entity and all we're going to i'm going to keep this simple let's just add a text let's add the dot name and it's optional so if there is no entity name let's do the double question marks and we'll just say no name all of our fruits have names so we're not going to run into this error anyway all right i think that's it for coding for right now that was a lot of coding i hope you're still with me let's click play on the simulator and see if it works all right i'm loading the screen and we have no fruits yet but if i add a fruit i'll say apple click the button which we should make say save and i will click the button and edit our apple let's also change the list so it doesn't look this ugly on the list let's add a dot list style and we'll do plain list style open close the parentheses so this should look better as well let's rerun the app one more time all right our button should say save the list looks a little better it says apple i can add another orange and you notice that the apple saved between sessions because it was saving the core data and then loading in core data so if we kill this app and i reopen it it still saves let's add some delete functions and update functions like we did in the last video so when we delete we can call on the for each we'll call dot delete on delete sorry and we can perform an action with an index set so i'm gonna just create that function up in our view model so i'm going to go into the core data view model up here right below where we have add fruit let's call funk delete fruit let's pass in an index set of type index set open the brackets and we'll do this logic in a second but let's just call this from our from our view so going back down i'm going to get rid of this brackets here and we're just going to call vm dot delete fruit and it already has our index set here but we don't even need that so i can just delete this index set and our super short code now says vm.delete fruit and just by adding that to our code if i rerun it this is this is how cool the for each in a list is this on delete automatically adds the swipe to delete which is so handy but if we click it obviously it doesn't delete yet because we haven't added that code so back in our function to delete fruit we need to find the entity that is at this index set so an index set could have a bunch of indices but we know when we're swiping this that it's really just one so let's just say let index equals index set dot dot first and this is optional so we'll say guard let index equal indexes first else return and then we'll say let entity equals saved entities and we'll access the index so this is our entity and then we just need to call container dot view context dot delete and we can pass in our entity now just like when we added we added our fruit and then we had to click save and now we are deleting our fruit and then we have to click save so this is why we created our own function here because we can just call save data again and lastly i want to create a function so that we when we click on this word apple we can update it now we're not going to add a custom ui for updating but really simply when we click on apple we're going to add an exclamation point to this word apple so let's create a funk update fruit we're going to open close parenthesis and open the brackets now we're going to call this from in our view and i just want to point out that get this on delete gave us an index set and that's why we use an index set but if i add an ontap gesture here onto the actual text we can use the entity directly so we don't even need to deal with the indexes so when i create this update fruit we're just going to pass in the entity directly and it will be a fruit entity so let's call that back in our tap gesture we'll call vm dot update fruit and we'll pass in the entity all right let's finish up the code here in our update fruit all we need to do is take the entity and modify some of its variables we only have one variable which is the name so let's say let current name equals entity.name and this is optional as we know so let's just do the double question marks and let's just leave it a blank string if there is no name we'll say let new name equals the current name plus an exclamation point and then we'll set the entity dot name equal to the new name and just like we did when we delete and when we add we need to then call save data that simple let's click play to rerun our app and i hope this works we have the ability to add fruits watermelon we have the ability to delete fruits and we can update fruits when we click on them it'll add the exclamation point and if i close the app and reopen the app it should now save in that state all right guys so there's a lot of code today and a lot going on in this video but what i really want to point out here with this mvvm method is that in our view which is the core data bootcamp view here we don't have any logic that is dealing with downloading data updating data saving data all we have is a reference to the view model right here and when we go to call something to change the data like adding a fruit we call view model and then add fruit and then all the logic for adding a fruit is in that function just like when we call update fruit or delete fruit all that logic is in the view model so our view here is dedicated to the actual ui this is just dealing with the front end of the ui and every time we need to actually access or change the data that's all being done in the view model so in our view model we have all of this logic up here which is as you can see is actually a lot of logic and this is a pretty simple app so when you have more complex data this logic will get much much longer and that's why it's important to separate the different layers in your app so in this core data view model we have all the logic for updating this data downloading data saving the data etc so i hope you guys enjoyed this video i know core data can definitely be confusing a couple notes to just point out is the main thing you need to do with core data is set up your persistent container and that persistent container is this file we set up here and in here we can add our entity we can give it a whole bunch of attributes if we wanted to give it more attributes than just the name we could have added that here and then when you go to fetch you just need to make sure that you have the correct entity name and of course the correct entity type so as you can see these calls to actually fetch from core data and to save to core data are relatively easy they're relatively short and easy to use you just need to know how to use them so i hope this video helped someone out there because i know core data is a challenge if it did and you're enjoying my content it definitely hit the subscribe button i got a lot more videos to come i'm excited i hope you guys are excited thank you for watching as always i'm nick this is swiffle thinking and i'll see you in the next video
Info
Channel: Swiftful Thinking
Views: 8,016
Rating: undefined out of 5
Keywords: SwiftUI Core Data, Swift Core data, How to use Core data in SwiftUI, How to use CoreData in SwiftUI, SwiftUI core data mvvm, SwiftUI Core data with MVVM, SwiftUI Core Data in View Model, SwiftUI Core Data ViewModel, MVVM Core Data, Core Data with MVVM, How to use Core Data in SwiftUI, How to use Core Data in MVVM, How to add core data to SwiftUI app, How to add core data to SwiftUI, SwiftUI core data, mvvm core data, Core Data with SwiftUI, Core Data SwiftUI app
Id: BPQkpxtgalY
Channel Id: undefined
Length: 29min 54sec (1794 seconds)
Published: Thu Apr 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.