Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  • Overview
  • Transcript

2.4 Manipulating Data

Hi and welcome back to Get Started with Core Data. In this lesson, we will add functionality to create, modify and delete data in our Core Data database. Let's start with CreateQuizViewController. First, I have to import Core Data and then set a few variables we're going to need. The first one is the coreDataStack, right in our table a view. As well as a quiz variable that will be used for editing an existing entity. In the course project populating the input field and selecting a date is already hooked up. We want to focus on saving to the store. Last let's get a reference to the managed object context. I told you before that I won't store it but this is inside a single function call, so it's fine. Creating and editing an entity are quite similar actions. If we create one, we need to do some additional work to insert it into the context. To check if we need to do this work, we can check if the quiz is present in the controler. You first have to call performBlockAndWait on the context. This is necessary to run on the correct thread, in our case, the main thread. Since we need the result of the call, we want to wait for it. Normally you would think that executing a block synchronously on the same thread would lead to deadlock. But those methods supports reentrency. This means nested calls in the same thread to perform BlockAndWait won't cause backlog situations. To create a new entity in the context, we first need to fetch the entity description for it. We can do this by calling entityForName and providing the entity name and context. Finally, we can initialize the quiz object. And here we need to provide the entity description as well as the managed object context we want to insert it in. Since we now have a valid quiz object, we can set properties on it like usual. Like the name as the value of the name field as well as the date from the date value variable. To persist the data we need to perform another block. This time we don't care about the return value so we can do it asynchronously. Persisting data in a context is done by calling safe on the managed object context. I don't want to care about errors this time. That's why I'm using the tryBang prefix. After we are done saving we can dissmisModal to leave the screen. While we are here we can also handle the editing action. The savesSquares function is exactly the same. Nothing changes, the only thing to do is to populate the variables unfiltered load. In this function, let's check if we have a quiz, and if so, we can set the name field value. If we also have a date, we can set the dateValue. A class already uses the date to fill the date field. A QuizTableViewController needs to pass the Core Data stack to our createViewController. We can use prepareForSegue to pass it on. We want to start the controller in a variable, since we have two possibilities the destination controller can look like. In the case of to createViewController. It is wrapped in a UINavigationController. When we transition to the questionsTableViewController we have access to it directly. To make this as generalized as possible, I'm going to check if the destinationViewController on the segwue is of the UINavigationController type. If so, I'm going to set the controller to the top few controller of this navigation controller. Otherwise I can set the controller to the seguesDestinationViewController. I need to push the Core Data stack to this controller, but we can't guarantee that this property exists. We could either use an extension to add it to all UIViewControllers. Or, and this is what we will do, add a protocol so that our ViewControllers are Core Data enabled. I'm going to add this in our Core Cata spec clause. The protocol is called core data stackable and can only be applied to a class not a stack. Here we can require a variable and also add get and set since it is a protocol. Now we can change the controller to be of type coreDataStackable and also forcefully cast your assignments. This way we can set the stack. Another thing I noticed we haven't changed yet is the reuse identifier and solve for it in xpath. Before we can try it out, we need the controller to conform to the protocol. Okay, let's build and run and add a new quiz. I'm going to name it Big Fat Quiz Of The Year because I love that show. After adding it, it shows in the list. Awesome, this means that all the code we wrote in the last lesson did indeed work. But watch what happens if we restart the app. For once it throws an NSRangeException which means that our cache is corrupt. I set quizCache and the last episode without much explaining. But until the lesson on performance, I will need to delete it before hand. This can be done by calling and NSFetchedResultsController that delete cache of name. The thing I wanted to show you and the reason why the cache is corrupt is that we no longer have a quiz in our cloud data store. Do you remember in our first lesson, when talking about the stack design patterns, I said that the safe gets pushed up one context. Well it did that but our parent context didn't do anything with it and didn't actually save it to the store. To remedy this situation, we need to extend our stack a little bit. In the main context setup function, we can add an observer on the default notification center. Which will be the CoreDataStack class, and it will call the SelectorStackDidSaveNotification. We are going to list on NSManagedObjectContextDidSaveNotification events on a managedObjectContext which has created in this function. If you have worker threads below the main context and you add this notification of server for them as well. Changes will bubble up all the way to the persisting context. Since we are good citizens, we are going to remove all of servers in the initializing. Let's put a notification handling in another extension. I need to prefix or add objective to C to be able to use to selector when adding the up server. The function will receive a notification object. First we need to check that the notification object is an NSManagedObject context with a guard clause. [BLANK AUDIO] >> We are also verifying that the parentContext has changes, otherwise, we don’t need to save. I’m going to wrap this in a dispatch group that can be used to wait until saving is complete before doing anything else. In the performBlock of the parentContext we are going to try and save the block and after we have done that we are going to leave the group again. A short post production notice leaving the group should, of course, happen inside the block. You need to shift the dispatch group leaveCall up two lines. Okay, let's try it again. I'm going to create a new quiz like before. It still stores it in the main context. So let's find out what happens if we restart the application. It is still there. Let's also try our sorting algorithm. I'm going to use the last year, and it should be at the bottom of the list. And it is, great! Now we need to implement the hooks for editing and deleting. I'm going to start with the delete since it is simpler. The tableViewDelegate has a function called commitEditingStyle that will get called when deleting data. There is already a template for it in this class that was generated by Xcode. We don't need to delete the row itself in the table view, the fetchedResultController handles that. We need to delete it in a managedObjectContext. Once again I'm going to get the reference to the context and perform a block on it. I can call deleteObject on the context and pass that the object on the fetchedResultsController that is at this very indexpath. Again I need to save the context. This will trigger our fetchedResultsControllerDelegateMethods. Let's try it. I'm going into edit mode and delete the row, and it's gone. We can tell that it's working since we didn't do any modifications to the TableView, just the context. To handle editing we need a way to trigger the correct segue and pass the Quiz object to it. Before we can do that we are missing the segue names in the story plot to identify which segue we are currently working with. One, I will call ShowAQuestionsSegue, and the other one is going to be GridQuizSegue. We want to go to the input form, and we are editing and we select the row. And prepare for segway, we can add another condition. If we have to create QuizSegue and we are editing the TableView and the sender as a quiz object, we can cast the controller to be CreateQuizViewController and pass the quiz to it. But how do we get to this point? Normally, when a row gets selected it will call the showQuestionSegue. There is a shouldPerformSegueWithIdentifier function where we can check if we have the showQuestionSegue and we are editing. If both conditions are true, we don't want to perform it. Normally during editing, selecting a row is disabled. To allow it we can set TableVieldAllowsSelectionDuringEditing to true, and view that load. The final method we need is didSelectRowAtIndexPath. Here we need to check if the TableViewIs.editing. If so we can call performSegueWithIdentifier and pass to CreateQuizSegue. As well as the Quiz object that is associated with this row as the sender. If we build and run and are within the edit mode, I can select the row and it will open the input dialog and populate the values. To test updating, let's change the values, and they're updated, great. In the next lesson we will work with relationships, specifically the questions of a single quiz. See you there.

Back to the top