The course is part of this learning path
This course focuses on a concept known as core data, which will allow us to store our data in a database. We'll then show you how to apply this concept to a real-life app which we will build called Art Book.
Learning Objectives
Learn how to create a local database allowing users to save data on their phones using core data
Intended Audience
This course is intended for beginners who want to learn how to build apps using Swift.
Prerequisites
To the most out of this course, you should have some basic understanding of programming and computer science in general.
Hi, within this lecture, we're going to learn how to save data in our Core Data database so that we can reach them whenever we want. So far, we have our image, we have our name, artistText and yearText, so we are ready to save those information in our database. And remember, in order to do that we're going to leverage the app delegate functions that are automatically created for us when we chose Core Data check box when we first create this project. And Core Data actually has a square-like database. If you have worked with SQL before, it's very similar but we're going to use swift code rather than SQL code. So, if you come over here to save context, you can see this is a Core Data saving support function. And we're going to see how to use that but for right now as you can see it's saving this with a context and it's doing something different that we haven't seen before. It's doing a do try catch. So, sometimes when we do some operations like going through the Internet with the URL, it can throw an error. Throwing means it can cause an error, okay?
So, it becomes irretrievable function and when we come across in a situation like that, we have to do this do try catch. It means that try this and if we get an error rather than crashing all app, just catch this error and try to find a solution to that error or just display an error message. For example, if you're going to a URL in the Internet and if you're trying to get data out of that URL, we can in fact, write URL in a wrong way so it can cause problems or URL can be changed over time and this may cause some problems. So, we're going to do some context.save here and we're going to write some entity names, class names. There can be some problem and it throws an error and we have to catch this error if we don't want to make our app crash. So, we're going to use those do try catch thing a lot. So, let's go to our saveButtonClicked in details, we see and try to reach that appDelegate functions. In order to do that, I'm going to assign appDelegate as a variable inside of my code. So, I'm going to say this is going to be an appDelegate. And I'm going to take this from UIApplication. So, this brings us the application itself actually. And if you say .shared, it will give me the instance of this app. And wherever or whenever I type UIApplication.shared, it brings me the only instance that this class has. It's kind of the thing that we're doing with user defaults. Remember, it returns the same instance and this returns the same instance as well, so that we can reach the same value from everywhere inside of our app. Later on, you're going to say .delegate and this will give us the delegate itself. And we're going to cast this, force cast this actually, as an AppDelegate with a capitalized 'A', not UIApplicationDelegate but AppDelegate, okay? With the uppercase 'A'. So, now I reached my AppDelegate with a variable. Now inside of this AppDelegate, I have a context that I want to get. So, I can do this on the same line as well, but it will be too much complicated. So, I'm going to go for a separate line. I'm going to say context appDelegate, the small one, okay? This one, it's our variable appDelegate.persistentContainer, okay? So, this is the container that our Core Data is saved in, and then Context, viewContext. So, this is an NS managed object. We're going to work with NS managed object in the Core Data. When we retrieve something from Core Data, it will be returned to us with an NS managed object type. You're going to see, don't worry. First of all, we have to learn how to write data, later on, we're going to see how to retrieve. So, when I say context.save, it says that it's going to throw an error. It may throw an error, as you can see. So, I cannot just go over and say context.save, I have to do this with do try catch. So, that's what I have been talking about. But before we do that, we have to come up with a way to write our data in the database anyway. So, let me show you how it's done. We're going to create a variable called newPainting or newArts. It doesn't matter, I'm going to call it newPainting because our entity name is paintings, okay? And this newPainting, we'll derieve from the entity that we have created. So, you have to say NSEntity and it doesn't work because we haven't imported Core Data in here. So, we have to do that first so that we can reach the Core Data objects. So, once we go here and we can just say close down the series. And now I can say NSEntity, okay? And as you can see, NSEntity description comes up. So, this is a description of the entity in Core Data. And we only have one entity but we can have multiple as well. If you say .insertNewObject, it will ask you for an entity name and it will ask you for a context. So, this is easy right now, right? We have the entity name as paintings and as for the context itself, and we have already created it. So, here our context. Here is our context. So, you can just say context in here. Now that's good. We have our newPainting model, newPainting object done. We can add whatever information we want using this entity in here. Now we have to go over attributes one by one. So, what do we have? We have name, we have the artists, we have the year. So, let me say attributes and I can just say newPainting. not ad but setValue, okay? So, this is going to ask me for a value and the key. So, this is very simple, like user defaults. Right now, forKey I have already defined the keys, right? I have already defined the attribute's name. So, if you come over here, you will see that we already have our attributes defined in here. Now all we have to do is just use the exact same names. For example, in the key I'm going to go for name first. So, for value I'm going to go for nameText.text And I can actually make this force unwrapped, and for the key I'm going to go for name. So, let me say newPainting.setValue. Now I can go for artistText, right? So, I can go for artistText.text and for the key, I'm going to say, "artist". So far so good. Right now, we're going to have year, okay? So, I'm going to say, setValue and I can get the yearText.text but I have to convert this to be an integer first. And in order to do that, of course, I'm going to use an if let like we did before. So, I'm going to say if let year integer and I'm going to take this from yearText.text, okay? And I will try to cast this as an integer like this and if this works, I'm going to say... let me just delete this, I write it from here once more. So, newPainting.setValue and the value will be here and the key not yearText but the year and the key will be year again. Okay, so there are two values left, first, ID and then the image. ID is actually very easy to create because as I said before swift will take care of this UUID thing by itself. All we have to do is just say newPainting.setValue and the value and the key actually, will be ID, okay? This is easy. And the value will be a UUID, okay? So, if you say UUID, open close parentheses, it will create an ID for us. This is a universal unique ID and every time we do that, it will create unique value for us. And this will be kind of a gibberish string text and we're going to see later on. Don't worry, we're going to see what it looks like but it will just give us a unique ID. And this will do the job for ID. Right now, we're going to learn how to get an image because if we want to save the image into Core Data we have to convert this into a data, binary data first, as we have seen before. Because we couldn't choose UI image in the Core Data, we have chosen the data, binary data, right? So, let me create this data from imageView.image and it's fairly easy to do that. All you have to just say, imageView.image and there is a method from that image to create data. And in fact, you can even specify the compressed size when you do that because if you have something like a big picture like three mega bytes, two megabytes, you want to compress it once you turn it to a data so that it won't take too much space in the database, so it won't actually slow down the process of reading or writing information, okay? If you say .jpeg data it asks you for a compression quality, as you can see, and we're going to use this. So, for compression quality, I'm just going to go for 0.5, for example, if you make this lower the quality will be lower, if you make this higher the quality will be higher. But the iPhones actually take very good pictures right now. So, they will have high quality even if we do this with 50%. So, I believe going with 0.5 or 0.4 is going to be sufficient for us because we're going to display this in a small UI image view anyway. So, this is kind of optional right now, I can make it force unwrap and in order to check this, we can have a lot of different kind of control mechanisms like, I can make my button not enabled so that, whenever a user chooses an image, then we can make this enabled or even if we don't do that we will have our own select image, jpeg, anyway so it won't crash. And you're going to see what I mean once we do the button thing but for right now, I'm going to say setValue data for key image and now we are ready for attributes. I have name, I have my artist, I have my year, my ID, and my image. Now, I can just call context.save. But again, this will give me an error. It will ask me to wrap this inside of a do try catch structure. So, how do we do that? You can just say, do, open curly braces, and under do, you you can just say, try this, okay? So, I'm going to try and save this context. And if it throws any error... let me delete this, I will catch the error in here and I will display a user, something like an alert message maybe. Right now, I'm just going to say, print error. And if it saves, I'm just going to say print success so that we can keep track if we made this save to our database. Because we don't have any function to get our information right now, all I want to is just test this and see if we can actually save this to our database, so that in the following lectures, we're going to see how to retrieve this information as well. So, let me open this. Let me choose one of the pictures like this, okay? And for the name, I'm going to go for something like waterfall maybe. So, this is kind of a waterfall picture. Later on, I'm just going to get real pictures as well, like Mona Lisa, don't worry. So, Waterfall and the artist will be Da Vinci and the year is 1900. If I click on save and then this image, this name, this artist and the year will be saved on the Core Data. As you can see, I got the success message. Right now, of course, I cannot see this anywhere, I cannot be sure if this is saved or not but since I got the success message, it means that it got saved. Later on, I'm going to retrieve those information and I'm just going to try and show those names in here and once I hit that, it refreshes the view controller which is good. I can add another picture as well. I'm not going to do that right now because I'm not even sure if this works or not. We're going to do this after we finish retrieving information and displaying them in our TableView. And we're going to do the same button thing, enabling and disabling to make sure that image has been selected later on. Don't worry about that either. So, let's stop and continue within the next lecture.
Atil is an instructor at Bogazici University, where he graduated back in 2010. He is also co-founder of Academy Club, which provides training, and Pera Games, which operates in the mobile gaming industry.