SPEAKER: Let's take a look at how you can save data when you're making iOS apps. One of the easiest ways to save data in an iOS app is to use something called SQLite. Now, SQLite, is basically a simple SQL database where you can write queries from your Swift code and persist that data to disk. So when your user opens your app, does some stuff, closes it out-- when they come back, they can look at that data that they saved. So to start, let's look at just a few different queries that you'll probably write while you're writing some SQLite in your apps. The first query is a CREATE query that's used to create tables. So here we're going to create a simple users table-- just has two columns. One is an id. And this is just a unique id for each user. You can see here that the type is an INTEGER. We're using it as our PRIMARY KEY. So this is sort of a unique key that's used to identify each row and it's AUTOINCREMENT. And that means that each time we insert a new row into this table we're automatically going to create a new id that's one more than the id before it. Our other field in this table-- It's just a text field. We called it, name. So we can give our users a name. And we can put in any amount of text we want there. And then, finally, the start of this query just says, want to create a new table, but if a table already exists then don't worry about it, we're not going to do anything. And we're going to call that table, users. So that's how we can create a table pretty simply in SQLite. The next query we're going to look at is inserting data into the table. To insert a new row we're going to start our query with, INSERT INTO, followed by the name of our table. So that's, users. And then, a list of the columns we want to supply values for. So here, we're just going to supply one column, and that column is called, name. Then we'll say, VALUES, and then, followed by the values we're going to insert. So here, we're inserting one new row. And for the name column, we're inserting a value of, 'Tommy' After we insert data into the table, we probably want to read that data back somehow. So this is what a SELECT query looks like. We're going to start by saying, SELECT. Our * says, just give me all of the columns you have. We'll say, FROM users, which is the table we want to read data from. And then, we'll have a WHERE clause that filters down those rows. So this says, only give me the rows where the name column is = to the text, 'Tommy' After that, we have an UPDATE query. So we want to start our query by saying, UPDATE. Then we have the name of the table, which is, users. Then we're going to say, SET, and say our column name, which is, name. And let's say a value of 'Tommy M' and then we want to filter down to some list of rows. We'll say, WHERE name = 'Tommy' So this query says, for every row where the name column is exactly the string, 'Tommy' I want to change that and update it to instead be, 'Tommy M' And so these queries are fairly simple. And you'll often find that the queries you're doing in your app are also pretty simple because you're usually just sort of storing values and reading them back. And oftentimes, you're not doing more complicated SQL operations, which is nice. So let's now take a look at an example of how we can call those SQL queries from our iOS app. And the app that we're going to be making here is a Notes App. So this is an app that's pretty-- it's already built into iOS. It's pretty simple. But you'll be able to create notes. You know, write down some note, it'll be saved to a SQLite database, and then you can browse and read them later. So let's jump in. First, we'll open up Xcode. As always, we're going to start by creating a new Xcode project-- just a regular single view app and we'll call our project, Notes. Just save it on the desktop as we've been doing. And by now we're pretty familiar with the code that's generated. So let's first open up that storyboard and think about what we want our app to do. So the first view in our app is going to be a TableView. That makes sense because each row is just going to represent a different note. And then, we're also going to have another ViewController in the app and that's going to be the actual NoteView itself. So it'll be basically a big editable text field where you can type in a note and then when you go back to that TableView we'll make sure to save that note to Disc. So a lot of this should feel pretty familiar. So let's jump in. First thing we want to do is change to a TableViewController just like we did before. So let's just delete that. Come up to our top right. Create a TableViewController. We know that we want to have some kind of Navigation Controller. So, again, we can just embed in a Navigation Controller. By the way, you can also just add a Navigation Controller from this View. It will actually automatically create a TableView for you as well. So just like before, let's set some properties on that cell. We're going to say it's same-- that basic style we had before. Let's call it a, Note Cell. Set our accessory to a Disclosure Indicator just like we had before. And now let's give this a title, which is, Notes. So that's a start that's our first screen. And those are all the Views for that first ViewController. Next, let's create our model. So let's create a new file-- just an empty Swift file that we can use for our Notes. So let's just call it, note.swift. Now maybe to start, let's just define a struct where we can have a Note. And we can have a couple different fields in that Note. First, we're going to have an id. It's going to be an integer, sort of just like the queries that we just saw. And then, there our other field can just be the contents of that note. And we'll just use a string for that. So that's our struct. Let's come back to our ViewController. So just like we did before, let's make this, TableViewController. We're going to store, in memory, a list of all of our notes so that we can display them in the table. So let's do that. Let's say that we have some Notes. It's a list of [Note] and it's initially empty because we haven't loaded anything. Now remember those three methods we have to implement on a TableViewController. The first is numberOfSections. It's just 1. We're not worried about sections right now. Second one is the numberOfRowsInSection. Now, just like before, the number of rows in our Table is just going to be the size of this notes array. And basically, as the user is adding notes and saving them, we're just going to continually update this notes array. So finally, the third method we have to implement is the cellForRow indexPath. And recall that all we're doing here is we're grabbing that cell from that pool, we're going to change some properties on that cell based on the data, and then return it. So remember that to grab a cell all we say is TableView, dequeReuseableCell. We had a note an identifier of, "NoteCell". And we can pass in the indexPath. We can say we want the Tax Label to just be our notes. Remember, we're using indexPath.row because we're using rows and not worried about sections right now. And then, we can just set it to be the contents of that note and return to cell. So this is all really similar to what we saw in our Pokedex App because it's just sort of a standard simple TableView. So let's just run this just to make sure that everything displays and nothing looks off. So here's our app in the simulator. But you'll notice that it's totally blank. So something happened here. So let's see what our console says. This is pretty helpful error message. It says, failed to instantiate the DefaultViewController. Perhaps the entry point is not set. Now, remember what we did last time, after we created that new ViewController in our storyboard? We made sure that we set that is initial ViewController to be true. So if we come back over to our Navigation Controller open up the right hand panel, and make sure we have is initial ViewController, checked. Now after we've done that, we can rerun our app, and there we go. So this is a pretty skeleton version of our notes. And so now what we need to do is actually write the code to create, read, and update notes for the user. So let's start by creating a new class that's going to have methods for different operations on our Notes database. So let's jump back to our model file here. And in addition to having a struct representing an individual note, I'm going to create this new class that I'm going to call, Note Manager. And this is basically a class, which as it sounds like, for managing notes. So this is going to handle connecting to the database, creating notes, getting all the notes, and updating a note. So those are basically the methods that we're going to want to have in this class. Let's start by writing a method to connect to a database. With SQLite 3, your database is just a file on the user's phone. So you can think about this as just opening up a file on Disk and then using that as your database. So let's start by creating a method called, Connect. And let's get a path to some file on the user's phone. So let's create a variable called, databaseURL. We're going to use a built in iOS class here called, FileManager default, and URL. So there's a few different parameters here that basically allow you to specify where you want this file to be stored. So this first one says, what directories do we want to use? So we want to just use the User directory. Wouldn't really make sense to put this in Music or Photos or something. And so this directory is basically some space for your app to store some user specific files. Next is just some more search path. So we just want to use the userDomainMask. Again, we're just putting everything in sort of the users path. These next few parameters-- don't worry too much about. We can just say, no, here, that doesn't matter. And this last parameter says, if this file doesn't exist, do you want to create it? Which we do. So that's going to give us a path to some folder on the user's phone. But what we really want is a path to a file. So to do that, we're going to say appendingPathComponent. And then we're just going to call this file, "notes.sqlite3". So what this kind of long method is really doing is it's just a way to get a path to somewhere on the device where it's safe for you to save, read, and write, files. So you'll notice here that the compiler says a couple of things are wrong here. And the main one is that we need to add a try-catch. So, again, something could go wrong in this place. There could be a reason that you can't save files-- you don't have access to somewhere in the user's device. So if that happens it's going to throw an exception. So we just need to handle that. So just like we did before, we're going to put this inside of a do block. And then, going to catch the error. And then we'll just print out, "Could not create database." Again, if this were a real app you'd want to display some sort of error message to the user but we're not worried about that. And then lastly, we just want to put a try in front of this call. And so now, our build succeeded. Now that we have a path to a file on Disk, we now want to establish a connection to that database. And open up that file. So to do that, we want to have inside of this class, a handle to a database. Or just some sort of reference to one database. You don't have to keep connecting over and over again since connecting can be kind of slow. So we're going to create a new variable called database. And the type of this variable is, opaquePointer. So this basically says that this is a pointer to something, but we know that this is going to be a reference to our database. So with that, we can start calling some SQLite3 functions. So before we do, we just have to make sure that we import SQLite3. And now, after we have that line, we have access to all of those functions. So let's start. So the first function we want to call is, sqlite3_open. And this is going to take two parameters. It's going to take a file that we want to open up, and then, as its second parameter, we're going to say where we want to establish a connection to the database. So the first thing is just going to be that file name we just created. And then, the second thing is going to be our database. So a couple of things here-- so first, we want to change this URL to a path. So all we have to do is say URL.path. And then, second, is we want to give it a reference to that database. So this is basically the same as the pointers are in C. We want to give a pointer to this function so that it knows where to open the database. So if we just put an ampersand here, that's going to say, all right, here's the address of where I want you to store this connection to the database. Now, with SQLite3 functions, they can return a few different values. So we want to at least want to make sure that they're returning what we expect and not airing out. So to do that, we're just going to put it inside of an if. So we're going to say, if the open was successful-- so that's SQLITE_OK. So that means we're good to go. If not, again, you want to handle this somehow. But we'll just print out, "Could not connect." OK. So now that we've opened the database, the last thing that we want to do is create a Table. So we're going to use one of those Create Table statements that we looked at earlier. So let's say a SQLite3, we're going to use, exec. So this is basically saying I want to execute some query on the database. The first thing we need is a pointer to the database to use. So we're going to use that database pointer we created. Next, is going to be the SQL to execute. So here, I'm just going to create a table I'm going to say, "CREATE TABLE IF NOT EXISTS" notes. And we're just going to have one column in our table here. We're going to call it, Contents. And it's going to be, TEXT. Now, with SQLite3, it's actually going to automatically create an id column for you. And that column is going to be that Integer AUTO_INCREMENT and it's going to be called, rowid. So normally, I'd create my own id column here, but because I know SQLite3 is going to do that for me, I'm not worried about it. So last, there's a few other things here-- you don't have to worry about these. They're just sort of different options that we're not going to end up using. So we can just pass nil to all of them. So let's just make sure that this works. So again, let's just put this in an, if. Make sure that it's OK. If it's not, you can print out, could "Could not create table." OK. So that's it for our Connect Method. So now, we basically just got a path to a database file in the user's phone, we've opened it up, and we've made sure that the table that we need to exist, exists. Next, let's write a function for creating a new note. So to do that, we want to make sure that we're using this same database pointer. Because if we're not, we need to reconnect over and over again. That's going to be slow. So let's create this function here. We're going to call it, create. So the first thing we want to do is call, connect. So this makes sure that there's a database pointer. But we only need to connect once, so we can do something simple here, which is say that if database isn't nil, then we're done. So this just says if we've already connected to the database, don't do this over and over again. So any of our other database functions can just call, connect, and not worry about it because we know that, connect, isn't going to redo something if it's already been done. After we connect to the database there is a three step process to executing queries. We're going to prepare the query. Then we're going to execute the query. And then we're going to finalize it. So the first thing we want to do is prepare it. So to do that, we're going to create a new variable called, statement. It's going to have that same type before. It's basically just a pointer to somewhere in memory. And now we're going to say, sqlite3_prepare. You notice there's a few different prepare functions? We're just going to use v2. That's kind of the standard one. And so, looking at these arguments, looks like the first argument is a handle to that database. So we can safely use this here because we know that we've called, connect. Next is the SQL that we'd like to run. So we're going to write an INSERT statement. So we're going to say, INSERT INTO notes. The only column we care about is, contents. And then, we'll supply values of, let's just say, "New note". And so this means that every time we create a new note, we're just giving it some default text called, "New note". These other things here-- we don't have to worry too much about. Can just pass a -1 here. We're not worried about what that is. We can pass our statement. And then, we can just pass nil. We're not really worried about that -1 or nil. So now, just like we did before, we just want to make sure that this function doesn't return any errors. So we'll surround it with an, if. And say that, if it is-- OK, and we can move on. And let's just do a build-- just a sanity check. Looks like we have an error here. OK. So it looks like, here, we forgot that we're passing a pointer. So just pass in the ampersand to just get the address of that so that the function can use that pointer. OK. So now we have a prepared statement. And now our statement is ready to execute. And the way to do that is by calling this function called sqlite3_step. So we're going to say, if sqlite3_step-- and here, it just takes one argument and that's actually just the statement. And let's just make sure that this is OK, then we're good. So before we forget, let's just add a couple print statements. Again, you really want to handle these errors. But we're just going to print them for now. So you can say, "Could not insert note." And we want to say here, something like, "Could not create query." So for example, if there's a syntax error in your query, one of these might trigger. Now the last thing we want to do is just finalize that statement. And once you finalize the statement, it's basically going to do some cleanup work. And it means you can't use the statement again. To do that it's also pretty simple. I'm just going to finalize the statement. So now, I notice that the structure of this is a little weird. So let's just kind of change up how our logic works here. So, actually, the first thing is we want to change this to-- SQLITE_DONE. And let's just kind of flip the logic here. So we'll say that if this didn't work, then let's print, "Could not insert note." And then, let's similarly say, if this didn't work, then we can say, "Could not create query." And, you know, we can just sort of return-- and this is kind of nice because you're going to avoid having some crazy number of nested indents. So we can get rid of that and that. OK. So as one less thing-- often when you're inserting a new value, you immediately want to access the id of the row that you just inserted. So to do that, let's make our create function actually return an int. And the value we want to return is going to be sqlite3_last_insert_rowid. And we can just sort of pass in that same database. And so this is nice because now we're saying, well, we just created a new row. And maybe you immediately want to update it or do something with it. So this can tell you that id. But, again, we have this error here. All we have to do is wrap this in an int. You'll notice here that this function is returning a different type of number. Really easy to just cast to an int by surrounding it with int. And then, let's say, you know, -1, here, would indicate that the note couldn't be created. So now let's just do a quick build, make sure we're good to go. And we are. OK. So now that we've written a method to create new notes, let's write our next method, which is to get all of the contents from the database. So let's say we want to have a function called, getAallNotes. We know that this is going to return a list of notes. So just like before, we want to start by connecting to the database. And remember, if it's already connected, this function isn't going to do anything. Next, let's create a statement, just like we did before. And prepare it. So we'll say, let's prepare. We'll use the database. And this time, the statement that we want to use is a SELECT. So we're going to say "SELECT-- we'll use that automatically created id, that rowid, as well as, the contents FROM notes. So this will just grab everything in the database so you can access it. Just like before, don't worry about what this is. We'll give it a pointer to that statement so it knows what to prepare, and then we don't need this either. And then again, we just want to make sure that if this is not SQLITE_OK. Basically, if some error occurred, you can print, "Error creating select." And will return some empty array. Next, just like we did before, is we want to call, sqlite3_step to actually execute the query. Now, last time, because we were just running one insert we could just call, sqlite3_step, once. But this time, we want to run it for every time there's a row available to read. So to do that, we're going to use a, while, loop. So we can say, while sqlite3_step of our statement is = row. This means we have a row, and we've accessed it, we want to convert that to our note object. So first, let's just create a new variable where we can store our result. So this is what we're ultimately going to return from the function. It's going to be a list of Note and it's initially going to be empty. So now each time that we do have a row from the database, we're just going to add that onto this result. So we can say, result.append. And what this is going to do is add on a new element to our array. So these arrays don't have to be a fixed size. As we saw, we can sort of change them, and add and remove things. So this is just going to add an element to that array. And we want to add a Note. And just like before, we have this nice constructor that was generated for us by the struct. And so now, we want to access the rowid for id, and the string for contents. So again, we're going to use some SQLite3 functions here. So we're going to say, sqlite3_column_int. And so what this is saying is it's saying I want to get the value at some column, and I know that it's going to be an integer, so give me back an int. And that works out because our struct takes an int. So again, we're just going to use that same statement as before. And now we're going to take a 0 indexed list of columns. So the first column in my select is rowid, so we're going to pass a 0 here. So that's our id. Next, we want to grab a string. So we're going to say similarly, sqlite3_column_text. Same thing as before, (statement) and now our contents is the first column. So now, one last step is we want to take this string and just convert it to a native Swift string. So all we want to do is say, string-- and what's coming back now is called a cString. And so what's nice is that string has this constructor that just takes a cString and converts into a regular Swift string. It's sort of this lower level API, similar to how we're using pointers and strings and c. So this is just an easy way to convert them. And then last, we have the compiler, hopefully telling us to just make sure we wrap this in an int, which we've done. So now, if we build this, as a compiler is reminding us, the last thing to do is just return that result. But before that, just make sure we call finalize on the statement just to do any cleanup behind the scenes. So now, if we run, build, we're good to go. So every time you're writing these SQLite3 queries you're basically going to be following the same pattern. You're going to take a statement, you're going to prepare it, then you're going to execute that statement-- either in a loop or just once. Then you're going to grab-- if it's selectory-- grab some of those column values. And then, lastly, finalize it. So that sort of pattern is going to apply no matter what you're doing with SQLite3 on iOS. So now, we've got enough to populate our TableView because we can start creating notes, and then, we can fill them up-- or display them in the TableView with this getAllNotes method. So let's start doing that. The first thing you want to do is to create a button to create new notes. Because right now, there's no way in the UI to add a new note. So we're going to use a BarButtonItem again. So just come back here, BarButtonItem-- add that up here in the top right. And now, we can take advantage of some built in system icons in iOS. So if you come over here to System Item, rather than being Custom. If you just set it to Add you get this nice looking + for free. So no need to download images from the internet or something like that. So that's done. And now, let's add an Action. So notice here, we're out of our model. We're back in our Controller. And we're going to create an Action. And let's call it, createNote. And now, we want to create a note. So the first thing we want to do is somehow get an instance of that Note Manager. Right now we have a bunch of methods, but we don't have any Note Managers created. But remember we talked about how we want to save this connection to the database since connecting can be kind of expensive? So what we want to do is actually create an instance of Note Manager inside of itself. And if you're familiar with Object Oriented Programming this is something that's called a singleton, which means that we have this class but there there's only ever going to be one instance of it. And we've actually already seen singletons. This, for example, is one. File Manager is a class. And by saying, default, we're saying give me that one instance of that class. So we're basically going to follow the same pattern here. To do that, we're going to say, static let, and let's just call ours, default. Or let's call it, main. You can call it whenever you want. And then we're going to set that equal to a Note Manager. So it's kind of this cool thing where a Note Manager has a reference to itself. And by saying, static, that basically enables you to access this property without an instance. Which makes sense, because if you had an instance, you wouldn't need another instance. And so, similarly, how you could say, FileManager.default here, we're going to be able to say NoteManager.main here. One other thing you might want to do if you're writing singletons, is just to make it so that no one else can instantiate your class. So to do that, you can create that init method, but mark it as private. By prefixing this with, private, we're basically saying, nobody else can call this. So even if you try to instantiate a NoteManager, the compiler is going to tell you that you can't. This is just kind of a nice thing to, you know, if you're giving an API to somebody else, or even just working with somebody, to sort of enforce and remind them that they should be using this singleton instance and not trying to create NoteManagers themselves. OK. Great. So now, we have an easy way of accessing the NoteManager, we can just say NoteManager.main.create. And that's going to create a new note. And it's going to give us back an id, which we're not too worried about right now. So we can just say, let_ = that. We're never going to use the value of that underscore. So now, what we've done is we've inserted something into the database and now what we need to do is reload the TableView just like we did before. So let's write a method that reloads the TableView. And this method needs to do two things. The first thing it needs to do is say, give me all of the notes that are currently in the database so I can display them, and then, let me tell the TableView that it needs to reload its data because you've changed that underlying data structure. So let's do both of those things. Recall that we had this property called, Notes. And this is going to hold all of the notes that the user has created. And let's set that = NoteManager.main.getAllNotes. Make sense? That's just going to return a list of notes, and so we want to save that. After that we want to call self.tableView.reloadData just like before. You'll notice that we didn't need this dispatch.main.async thing this time. The reason is that we're not inside of a background task at this point. Everything happening here is in the foreground, and so there's no need to sort of jump back into the foreground because we're already there. So after we call createNote, we just want to call reload. And that's going to reload the entire table. Didn't end up using viewDidLoad here so let's just remove that for now. So one last thing to do before we can run this app is remember to hook up this IB action. So let's jump back to our storyboard. Let's select the TableVIewController. And first, let's make sure that it's using the Class that we specified. So let's change the Class to ViewController, which is the Class that we were just writing. Then, let's Control, Click, and Drag, from the + over to the ViewController, and there's our Sent Action, createNote. OK. So let's run our app and see what happens. So here's our empty TableView just like before. Let's try pressing the +. OK. So that's not great. Looks like we've got some error messages. And these are error messages that we wrote. So that's helpful. So let's just jump back into our model. And-- ah-- so this was a-- I was wrong before. You want to save this in the Document Directory. So this is just basically a directory where apps do have permission to read and write. What was happening is we're trying to save it somewhere where we didn't actually have permission to do that. So let's try again. Let's rerun this. And, OK. So if you click +, there we go. So now we have added a new note. So what we've just done there is we've inserted a note into the database. We've notified our TableView that we need to reload. And then, we reloaded all of the notes back from the database so that the TableView is displaying the most up to date versions of all the notes. So let's just sanity check to make sure that these notes are sort of behaving as we'd expect. So let's stop the app. And now, when I rerun it, I should see the note again because that means that we're saving it to Disk. So let's click, Run. OK. And that's interesting. It looks like we don't see the note. So now, let's see. It doesn't look like there's anything wrong in our model because none of these print statements triggered. So maybe it's in the Controller. Let's jump back to the Controller and-- a-ha. So what's happening is we have this reload method but we're never loading it for the first time. So when that view is created, we want to make sure that we load the notes from memory right when that app starts up. So right now what's happening is it's starting up, it's saying, well, my notes are set to an empty array, , OK, I guess there's nothing to display. And so let's change that. So let's say, on viewDidLoad-- make sure recall the super method. And then let's just say, reload. And so what this is saying is when the app first starts up, fetch all the notes from the database, tell the TableView it's time to update. So now let's run this. And there we go. Just as we expected. There's our note. If we stop this and we create it-- stop this and rerun it, rather, there's our note. So there's one last piece of the puzzle here, which is creating a ViewController to display and allow the user to edit the contents of their note. And again, some of this should be pretty familiar. So let's first jump back to the storyboard to create a new ViewController. Add it there. Remember we want to add a Segue here. So we're going to Control, Click. Add that ShowSeque. Give it a name. So we'll just call it something like, NoteSeque. Let's create a new SWIFT file. And let's call it, NoteViewController. OK. Here's our NoteViewController. We're going to say, NoteViewController extends UIViewController. Make sure we've imported UIKit. Everything builds. That's great. Come back to the storyboard and make sure that in the Identity Inspector, we have set this to NoteVIewController. OK. So now, let's add a TextView that will display all of the contents of this note. So here, let's type in TextView, drag this over. And so now what we want to do, is we want this TextView to fill the entire screen. Much like it does in the iOS app. And so, to do that, we're going to use something called, Constraints. So if you come down here in the bottom right, you can see a few of these little buttons. And this third one here says, Add New Constraint. So let's click that. And we get these this little pop over. And what we want to do is you want to say, let's set the top of this view to be the top of the iPhone. The bottom of this view to be the bottom of the iPhone. And same for the left and right. So to do that we can just constrain all four of these things to its parent. So when we say, Add Constraints, we can see these sort of little lines that indicate that they're going to sort of stick to the edges there. So now we can just sort of drag this over, drag this over, and we're good. So we can get rid of this sort of default text. It was kind of silly. Get rid of that. And then we'll also make sure that our TextView is editable, which it is. And so now, our View, should all be connected. So let's jump back to the model and write the last query that we'll need to write, which is to save a note to a database. So we're back in our NoteManager here and we're going to create a new method called, save. This method is going to take one parameter and it's going to be a note that we'd like to save. So we're going to say, Note, here. And it's going to follow that same pattern that we saw before. We're going to call, connect. That's going to establish a connection to the database. We're going to create a statement. It's in the OpaquePointer. We're going to try preparing a statement. So, sqlite3_prepare. It's going to take a database. And now we're going to write an UPDATE statement. So we're going to say, UPDATE notes. The only thing we're willing to set is the contents. So we're going to say, SET contents. Now we're going to add a question mark here. We'll come back to that later. WHERE realid = ? As always, we don't worry about this. This is a pointer to our statement. This we don't need. And so, make sure that this is OK. It's error messages helped us last time, so I'll do it again. OK. So now what we want to do is we want to bind data to this query. So these question marks here are just a nice way of passing data into a query. You could use something like string interpolation. But it's kind of insecure and you're opening yourself up to someone sort of doing things with your app that you might not want them to. And basically, open to a single injection attack. And so we want to instead use parameter binding to safely pass data into this query. So the way to bind data to a query is by using the SQLite3 Bind Methods. So you can say, sqlite3_bind_text, followed by that data type. So we're going to say, use the statement. The next parameter to this function is going to be the Index of the question mark you want to update. So what's kind of annoying about this is a one indexed list where the other 1 was a 0 index list. So to bind to the first question mark, you actually want to say 1, which is really easy to forget. But hopefully, this error messages will help you out. So then we'll bind that. The next thing is going to be the value we want to bind. And similarly, to hear how we wanted to change a regular Swift String into this cString-- we're going to do the same thing here. So the way to do that is to first create an NSString from a regular Swift String. So we're going to say, note.contents here. And then from there, you're going to call this other method called utf8String. And you don't really have to know the details of what's going on here. But basically, you're just converting formats-- converting the data between a Swift friendly format. And then the SQLite3 friendly format. Same as always, we're not worried about these last two parameters. So that's binding the first parameter. Now let's bind the second parameter. So let's bind the integer. This is a statement. Again, we're using a 2 here because it's a 1 index list. And now we want to set note.id. Let's build just to make sure. Looks like instead of an int, we need to use an int32. Easy to fix. Just surround your int with that. Now that you've bound the parameters to this query you want to execute it. So remember to do that, we're going to use the step function, pass in that statement. And then we want to make sure that it's done. If it's not then we'll say, "Error running update." Finally, we just want to finalize that statement to do that cleanup. OK. And so now, what this was going to do, is you can pass it in an instance of a note and we're going to write those values to Disk. Using an update statement so you can change the value of a note that's already exists. So that's it for our model. We've written the three model methods we needed to write. We can create Notes, we can get Notes, and then we can save Notes. So the last thing to do is wire all of this up to our Views through our Controllers. So we created that segue in the storyboard and so now we want to utilize that segue to pass the Note from this list to the other ViewController. So remember that method was called, prepare for segue. Let autocomplete do the work. We want to check in on that identifier. That identifier we called it, a NoteSeque. That's true. Just like last time, we want to cast that DestinationViewController to an instance of our NoteViewController. So let's do that. If let destination = segue.destination as NoteViewController. And so now, here is where we can pass the note. So let's jump to this ViewController, add a parameter for that note. Make sure that exists. While we're here, let's also define an outlet because we know we're going to need to connect that later. So let's say there's an IB outlet for the textView. Now from our ViewController we can say, destination.note. Just like before, we're going to use notes. And the index we're going to use is tableView.indexPathForSelectedRow. And we just need the row. So that's going to pass over the note data to our second ViewController. OK. So we've passed the note. So let's jump back to our NoteViewController. Let's fix this typo. So now, let's bind that text that we received from the note to our textView. So we're going to say viewDidLoad. Call, super. Then textView.text = note.contents. Now, this just says, whenever the View is loaded let's set the contents. Now, the other thing we want to do is save the note when the user exits the View. So to do that, we're going to use another iOS method that's called for us called, viewWillDisappear. And so this is going to be called automatically right when the user hits that Back Button and before the View has disappeared. So just like before, we're going to call, super, pass in that animated parameter. And then we're going to say, NoteManager, just like before, main. And now we're just going to save the note that we currently have. So let's build. Looks good. Now, lastly, let's not forget to connect this outlet. So come back over to main. We're going to select our NoteVIewController and then we're going to Drag and Connect the TextView property. And now, one last thing we need to do is make sure that we update that first ViewController every time the user comes back to it. So before, we used viewDidLoad but this is only going to be called once, which is the first time that the VIewController is created. But when the users jumping back and forth between these ViewControllers, every time you come back to the first one, you want to reload the data to make sure that it's updated. So rather than using viewDidLoad we're going to use viewWillAppear. So it's sort of the opposite of viewWillDisappear. But every time this View comes into focus, and into the foreground, this method is going to be called. So let's change our super.viewDidLoad to super.viewWillAppear to pass along that animated parameter. And now we can try running our app and see what happens. So here's the app in the simulator. From before, we had that new note and we persisted that. So that's going to be around. So let's click that. Great. Looks like we've passed the data from that first note into the second ViewController. Now let's try typing. Save this is a new note. Click back. Doesn't look like it worked. So even though we change the text when we came back, looks like the note that was displayed was this new note. So let's see what happened. Let's jump into our NoteViewController here and take a look at what we're doing. Looks like when the View loads we're setting the text = contents. That looks right. Then when the View disappears, looks like we're saving the note. But-- ah-- we never changed that note object. So what's happening is when the second ViewController receives that note object, it's just going to display it. And then no matter what the user typed in, just save it right back to Disk without being changed. So what we want to do is actually change this note object. So we want to set its contents to be equal to the contents of that TextView. So we'll say, note.contents = textView.text. Now, if we build here-- I think this is the first time we've seen this but we notice in the struck that we created let variables, which means they're immutable. So here the compiler is telling me that I declared contents as a let in mutable variable. Instead, I want to declare it as a mutable variable with var. So I'll come back to my struct, change let to var and try rerunning again. Here we go. So let's go into our new note, change this to this is my new note. Backup. And it looks like we're working. So just to make sure let's create a new note by tapping on the +. Let's save this one as Note 2. And there we go. It looks like everything worked. So there's our fully functional Notes App, using SQLite to save data on the user's phone.