0 1 00:00:01,030 --> 00:00:08,850 All right, so in the last lesson, we managed to get our swipe cells to work and we can now swipe on our categories 1 2 00:00:09,150 --> 00:00:12,990 to delete them, and then updates our model accordingly. 2 3 00:00:12,990 --> 00:00:19,440 Now, in this lesson, we're going to talk about how we can copy that functionality over to our 3 4 00:00:19,440 --> 00:00:23,550 TodoListViewController without having to copy all of the code. 4 5 00:00:23,550 --> 00:00:30,000 And we mentioned that the way that we're going to tackle this problem is by creating a superclass where 5 6 00:00:30,060 --> 00:00:32,840 both of these view controllers can inherit from. 6 7 00:00:32,850 --> 00:00:34,110 So let's go ahead and do that. 7 8 00:00:34,140 --> 00:00:35,560 Let's hit command N 8 9 00:00:35,880 --> 00:00:39,150 and we're going to create a new Cocoa Touch Class. 9 10 00:00:39,210 --> 00:00:45,340 And the reason is because we want to inherit from UITableViewController because both of these view controllers 10 11 00:00:45,390 --> 00:00:46,990 are TableViewControllers. 11 12 00:00:47,280 --> 00:00:52,190 And if we need some of that functionality, then we can inherit it over. 12 13 00:00:52,200 --> 00:00:59,070 So we're going to call this class the SwipeTableViewController and we're going to hit Next, and we're 13 14 00:00:59,070 --> 00:01:02,220 going to save it in our group of controllers. 14 15 00:01:02,430 --> 00:01:05,660 And now this is going to be our superclass. 15 16 00:01:05,790 --> 00:01:10,790 And so we need to add all of the swipe cell functionality inside here. 16 17 00:01:10,890 --> 00:01:19,380 So we're going to import SwipeCellKit, of course, and we're going to adopt the protocol which is 17 18 00:01:19,850 --> 00:01:31,380 SwipeTableViewCellViewCellDelegate, and I'm going to delete all of this stuff that Xcode 18 19 00:01:31,380 --> 00:01:37,740 has automatically put in here so that we have a nice and clean view controller to work with. 19 20 00:01:38,070 --> 00:01:44,720 Okay, so now we need to copy over everything, basically, that's inside our extension. 20 21 00:01:44,870 --> 00:01:53,160 So I'm going to hit Cut and I'm going to paste it over here. Now because this is a separate class that 21 22 00:01:53,250 --> 00:01:56,010 only deals with the swipe cell functionality, 22 23 00:01:56,010 --> 00:02:00,990 it doesn't actually make sense for it to be inside a separate extension because then our main class 23 24 00:02:00,990 --> 00:02:01,730 would be empty, 24 25 00:02:01,740 --> 00:02:02,060 right? 25 26 00:02:02,070 --> 00:02:03,330 That isn't making sense. 26 27 00:02:03,360 --> 00:02:11,670 So we can go ahead and take out our delegate methods from this extension by cutting it and putting it 27 28 00:02:11,850 --> 00:02:19,460 inside our SwipeTableViewController and we can delete our extension completely. 28 29 00:02:19,500 --> 00:02:27,020 So, now we have both of those swipe cell delegate methods inside our SwipeTableViewController. 29 30 00:02:27,330 --> 00:02:34,650 But one thing that we can't do in here is we can't delete our categories because, remember, if we're going 30 31 00:02:34,650 --> 00:02:42,000 to inherit this class inside both of these classes, we can't have any specific code relating to each 31 32 00:02:42,000 --> 00:02:43,230 of these view controllers. 32 33 00:02:43,380 --> 00:02:49,980 So the superclasses are not meant to have any knowledge of their subclasses or their children. 33 34 00:02:50,010 --> 00:02:55,110 So it sounds a bit cruel, but that's just the way it is. 34 35 00:02:55,290 --> 00:02:59,550 If you watch "Planet Earth," you will realize that the world is pretty ambivalent 35 36 00:02:59,580 --> 00:03:08,760 the struggles of individuals. And in the world of coding and Swift, it's also the same. Sadly, our 36 37 00:03:08,760 --> 00:03:14,550 SwipeTableViewController is going to have all of these children category to view controller and TodoListViewController, 37 38 00:03:14,790 --> 00:03:17,370 but it's not going to care or know about it. 38 39 00:03:17,670 --> 00:03:21,110 So there's a little bit of downer for you, but it will be okay. 39 40 00:03:21,120 --> 00:03:27,930 So I'm going to actually just comment out that block of code, and instead, I'm just going to write print 40 41 00:03:28,350 --> 00:03:34,800 "Delete cell," just so that we know that this is actually being called when we test it later on. 41 42 00:03:34,800 --> 00:03:35,100 All right. 42 43 00:03:35,100 --> 00:03:38,170 So I think that's all that we need to do over here. 43 44 00:03:38,430 --> 00:03:43,860 But let's head back to our CategoryViewController and delete that pragma MARK as well. 44 45 00:03:43,980 --> 00:03:50,970 So, now instead of our CategoryViewController inheriting from UITableViewController, we're actually 45 46 00:03:50,970 --> 00:03:57,180 going to inherit from the SwipeTableViewController. So we can go ahead and delete this and simply 46 47 00:03:57,180 --> 00:04:03,740 write SwipeTableViewController and that was our custom class that we created. 47 48 00:04:03,750 --> 00:04:11,640 So because we want to keep all of these swipe cell functionality inside the superclass 48 49 00:04:11,640 --> 00:04:12,520 SwipTableViewController, 49 50 00:04:12,720 --> 00:04:19,710 we actually don't really want any sort of mention to SwipeCellKit inside the subclass which is our 50 51 00:04:19,710 --> 00:04:21,190 CategoryViewController. 51 52 00:04:21,240 --> 00:04:27,910 So I want to be able to delete this import statement and to get rid of all of the mentions of 52 53 00:04:27,910 --> 00:04:35,220 SwipeCellKit. And pretty much, as soon as you do that, we get an error here that tells us, "Hey, by the way, 53 54 00:04:35,220 --> 00:04:39,300 you created the cell and you said that it has to be a swipe cell." 54 55 00:04:39,660 --> 00:04:45,480 And also you set the cell's delegate in order to allow the SwipeCellsDelegateMethods to trigger and 55 56 00:04:45,480 --> 00:04:47,500 inform this current class. 56 57 00:04:47,580 --> 00:04:56,160 So we don't want either of these lines of code. But the code that we do need is to change the textLabel 57 58 00:04:56,370 --> 00:05:03,180 based on the categories inside this view. And SwipeTableViewCell cannot know anything about those 58 59 00:05:03,180 --> 00:05:04,180 categories. 59 60 00:05:04,230 --> 00:05:07,380 So how can we square that circle? 60 61 00:05:07,770 --> 00:05:15,090 So what we can do is we can create the superclass table view cellForRowAt indexPath, and then we can 61 62 00:05:15,270 --> 00:05:21,300 override it over here and add a little bit more information to that cell. 62 63 00:05:21,300 --> 00:05:29,940 So let's, first, head over to SwipeTableViewCell and we're going to add some TableView Datasource 63 64 00:05:30,300 --> 00:05:36,970 Methods. And the one that we really do need is the cellForRowAt indexPath. 64 65 00:05:37,230 --> 00:05:40,680 And here is where we want to initialize the SwipeTableViewCell 65 66 00:05:40,680 --> 00:05:45,870 as the default cell for all of the table views that inherit this class. 66 67 00:05:45,990 --> 00:05:52,230 So we can go ahead and copy some of this code over and I'm going to delete this code that we copied 67 68 00:05:52,230 --> 00:05:57,590 over from the Swipe Cell Documentation just to make everything a little bit clearer. 68 69 00:05:57,990 --> 00:06:05,430 So let's head over here and paste that code in here. So you can see that what we did in CategoryViewController 69 70 00:06:05,430 --> 00:06:14,910 is that we created a new cell by dequeuing it using the identifier CategoryCell. Now, we can't have 70 71 00:06:14,910 --> 00:06:16,320 something called CategoryCell 71 72 00:06:16,310 --> 00:06:20,200 if this class doesn't know about it's subclasses, right? 72 73 00:06:20,220 --> 00:06:24,600 So we have to change this name to something more generic like just "Cell." 73 74 00:06:24,900 --> 00:06:32,430 And for that to work, we have to go back into our Main. storyboard and change both the identifier for 74 75 00:06:32,430 --> 00:06:40,410 the CategoryCell to Cell. And, also, because we want both the TodoListViewController and the 75 76 00:06:40,410 --> 00:06:44,910 CategoryViewController to use swipe cells from the SwipeTableViewController. 76 77 00:06:45,000 --> 00:06:50,110 We're going to rename the ToDoItemCell also to Cell as well. 77 78 00:06:50,130 --> 00:06:52,250 So let's hit save on that 78 79 00:06:52,410 --> 00:06:58,140 and let's go back to SwipeTableVieCell and you're gonna see that our identifier is now Cell and that will work 79 80 00:06:58,170 --> 00:07:01,200 for either of those subclasses. 80 81 00:07:01,200 --> 00:07:08,130 And then we get onto this line and this line basically can't exist because we don't know about categories 81 82 00:07:08,160 --> 00:07:09,780 inside SwipeTableViewController, 82 83 00:07:09,810 --> 00:07:13,310 and we certainly don't know about our data model in here. 83 84 00:07:13,320 --> 00:07:16,060 This is just a front-end UIClass. 84 85 00:07:16,230 --> 00:07:21,870 So we're going to go ahead and delete that and we're going to keep cell.delegate as self because 85 86 00:07:21,930 --> 00:07:26,820 this is the place that has all of those delegate methods that will deal with the deletions. 86 87 00:07:27,120 --> 00:07:33,690 And then we're going to return the cell. And that is all we need to do inside this superclass. 87 88 00:07:33,690 --> 00:07:40,080 Now, we're going to head over to our subclass which is the CategoryViewController and we need to fix 88 89 00:07:40,140 --> 00:07:46,380 some issues here because we need to be able to set the cell's textLabel.ext property to the name 89 90 00:07:46,440 --> 00:07:49,210 of the categories in our Data Model. 90 91 00:07:49,350 --> 00:07:54,910 But if we're not going to initialize the cell here, then how can we tap into it? 91 92 00:07:55,140 --> 00:08:01,740 So let's go ahead and delete all the bits of code that we've put in the superclass and we can tap into 92 93 00:08:01,740 --> 00:08:11,400 that superclass by saying let cell = super.tableView and the tableView is the same as the 93 94 00:08:11,400 --> 00:08:12,470 one we've got here 94 95 00:08:12,810 --> 00:08:15,810 and the cellForRowAt indexPath. 95 96 00:08:15,990 --> 00:08:24,720 So this is going to tap into that cell that gets created inside our super view and it taps into the 96 97 00:08:24,720 --> 00:08:30,000 cell at the current indexPath. And then we're going to take that cell and then we're going to add some 97 98 00:08:30,000 --> 00:08:31,450 more things to it. 98 99 00:08:31,590 --> 00:08:34,590 And that cell is already a swipe cell, 99 100 00:08:34,620 --> 00:08:41,160 but we're going to modify it further by changing the textLabel to the current category. 100 101 00:08:41,160 --> 00:08:45,310 And then finally, we're going to return cell after all of that work. 101 102 00:08:45,510 --> 00:08:51,310 So when this gets called, the first thing it does is, because we call super, 102 103 00:08:51,360 --> 00:08:57,400 it goes into our superclass and triggers the code inside our cellForRowAt indexPath, 103 104 00:08:57,600 --> 00:09:03,720 at which point, it creates a new cell from the prototype cell called Cell and it gets created as a 104 105 00:09:03,720 --> 00:09:04,900 SwipeTableViewCell. 105 106 00:09:04,950 --> 00:09:11,190 It sets the cells delegate as this current class which is the SwipeTableViewController to enable 106 107 00:09:11,190 --> 00:09:13,020 all of our delegate methods to work, 107 108 00:09:13,160 --> 00:09:20,350 and then it returns that cell. And that cell when it gets returned, it gets placed into here. 108 109 00:09:20,640 --> 00:09:27,780 At which point, we further modify it by changing the textLabel, and finally, return the cell to our current 109 110 00:09:27,780 --> 00:09:31,930 table view inside our CategoryViewController class. 110 111 00:09:31,980 --> 00:09:39,300 So it seems a little bit roundabout and it's all in the name of trying to modularize our code and trying 111 112 00:09:39,300 --> 00:09:43,020 to reduce repetition and keep our code dry. 112 113 00:09:43,050 --> 00:09:49,100 So let's go ahead and hit run and see if our app actually runs and produces those cells 113 114 00:09:49,230 --> 00:09:50,460 or will it crash and burn. 114 115 00:09:50,460 --> 00:09:55,830 So the moment of truth is now. So the first good sign is that we haven't had any errors and we've 115 116 00:09:55,830 --> 00:10:01,730 got both of our Category cells with the textLabel.text filled out correctly. 116 117 00:10:02,080 --> 00:10:05,390 Now, the question is, are these swipe cells? 117 118 00:10:05,410 --> 00:10:11,090 Because if it only use the code here, then they're just going to be normal UITableViewCells. 118 119 00:10:11,260 --> 00:10:17,650 But if our inheritance from the superclass worked correctly, then we should be able to click and drag. 119 120 00:10:18,010 --> 00:10:20,310 And there you go. There's our delete button. 120 121 00:10:20,530 --> 00:10:25,640 Now, if you click the delete button at this time point, it will crash your app. 121 122 00:10:25,720 --> 00:10:32,500 And the reason is because it triggers this particular delegate method which is going to try and remove 122 123 00:10:32,800 --> 00:10:37,970 the last row in our table view, but we haven't removed it from our data source. 123 124 00:10:38,050 --> 00:10:45,580 So the incompatibility is going to lead to this error where it says, "Invalid number of rows in section." 124 125 00:10:45,580 --> 00:10:53,440 So in order for that to work, we have to update our model. Now, because we can't call category inside our 125 126 00:10:53,440 --> 00:10:54,380 superclass, 126 127 00:10:54,430 --> 00:11:00,040 you have to realize that your superclass must know nothing about its subclasses, so we cannot use any 127 128 00:11:00,040 --> 00:11:03,830 of these bits of code. But we can trigger a function call. 128 129 00:11:03,910 --> 00:11:06,970 So let's create a function down here. 129 130 00:11:07,240 --> 00:11:12,820 So we'll call it updateModel and the external parameter will be "at," 130 131 00:11:12,850 --> 00:11:16,370 so we can call it like updateModel at this particular indexPath. 131 132 00:11:16,570 --> 00:11:23,910 But inside the function, we'll just call it indexPath and it's going to be of data type indexPath. 132 133 00:11:24,290 --> 00:11:30,870 And inside this function is where we will update our data model. 133 134 00:11:31,540 --> 00:11:34,540 Okay. So, now we need to call it over here, 134 135 00:11:34,570 --> 00:11:42,730 so we're going to call updateModel at the indexPath which is going to be the same one that triggered 135 136 00:11:42,790 --> 00:11:44,480 this delete delegate method. 136 137 00:11:44,650 --> 00:11:46,950 So we'll call it indexPath. 137 138 00:11:47,020 --> 00:11:51,460 And because we're inside a closure, we always have to add the keywords "self." 138 139 00:11:51,460 --> 00:11:59,080 And now we can cut this block of code and we can go into our CategoryViewController. 139 140 00:11:59,110 --> 00:12:05,920 Now, inside our CategoryViewController, under the Data Manipulation Method section, we've got save, 140 141 00:12:06,100 --> 00:12:14,200 we've got load, and now we're going to create a delete section and we'll call it Delete Data From Swipe. 141 142 00:12:14,230 --> 00:12:21,700 Now, instead of creating a method inside our current class, I'm going to override and call the superclass 142 143 00:12:21,700 --> 00:12:25,980 method which we named updateModels, 143 144 00:12:26,170 --> 00:12:30,960 so override updateModels at indexPath, 144 145 00:12:31,120 --> 00:12:37,260 wnd we're going to override that updateModel method that was specified over here. 145 146 00:12:37,480 --> 00:12:46,150 So when our deleteAction happens, it's going to call updateModels passing in an indexPath, at which 146 147 00:12:46,150 --> 00:12:46,600 point, 147 148 00:12:46,600 --> 00:12:53,150 not really very much happens, but we can tap into it over here by overriding it. 148 149 00:12:53,350 --> 00:12:58,900 So this is where we're going to paste that block of code and I'm going to uncomment it and shift it 149 150 00:12:58,900 --> 00:13:05,700 to the left a bit using command left square bracket, and this should take care of updating our model. 150 151 00:13:05,710 --> 00:13:08,290 So let's run an app and see if it works. 151 152 00:13:08,290 --> 00:13:12,070 All right so let's add a "New Category," 152 153 00:13:13,160 --> 00:13:19,480 hit Add. And let's just check to make sure that we've got a Delete button when we swipe on it. 153 154 00:13:19,520 --> 00:13:21,760 So that comes from our superclass. 154 155 00:13:21,900 --> 00:13:30,610 And now if I hit the Delete button, you can see that this delegate method deleted our category from our 155 156 00:13:30,620 --> 00:13:31,540 data model. 156 157 00:13:31,550 --> 00:13:37,820 So this is more of an advanced example of some of the things that we learned on objects and classes and inheritance, 157 158 00:13:37,910 --> 00:13:44,810 especially. And it's really, really key that you understand how subclasses, superclasses, overriding, how 158 159 00:13:44,810 --> 00:13:46,000 all of this works. 159 160 00:13:46,130 --> 00:13:53,720 So it's important that you play around with this updateModel function and also where you override it 160 161 00:13:53,770 --> 00:13:54,690 over here. 161 162 00:13:54,800 --> 00:14:05,260 For example, if we create a print statement here that just says, "Item deleted" from the superclass, and 162 163 00:14:05,260 --> 00:14:08,170 then we go over to our CategoryViewController. 163 164 00:14:08,500 --> 00:14:14,430 If we run our app as is, we are not going to get that print statement in here. 164 165 00:14:15,560 --> 00:14:22,550 And I'm going to show you by running our app and creating new category, hit Add, and I'm going to swipe it 165 166 00:14:22,550 --> 00:14:23,550 to delete it. 166 167 00:14:23,720 --> 00:14:24,830 No print statement. 167 168 00:14:25,100 --> 00:14:30,450 And the reason is because we've overridden how that method should function. 168 169 00:14:30,500 --> 00:14:41,320 But if we made a call to the super updateModels(at: indexPath) method, then we will get that print statement. 169 170 00:14:41,600 --> 00:14:44,220 So let's add a new category. 170 171 00:14:44,270 --> 00:14:52,880 And now if I swipe and delete, you can see item deleted from superclass. And that's all because of this 171 172 00:14:52,880 --> 00:14:55,720 call to the superclass method. 172 173 00:14:55,730 --> 00:15:01,950 So, essentially, what's happening is that our deletion triggers this delegate method. 173 174 00:15:01,950 --> 00:15:10,250 This delegate method has a closure which triggers the updateModels(at: indexPath) and it passes in the 174 175 00:15:10,250 --> 00:15:17,630 indexPath of the cell that got swiped. That calls this function over here which has a print statement, 175 176 00:15:18,140 --> 00:15:26,870 but this function is overridden in the subclass. And that subclass can either call the superclass method 176 177 00:15:26,930 --> 00:15:34,670 in order to run all the code that's currently inside here or it can simply override it without the need 177 178 00:15:34,670 --> 00:15:37,030 for any of the superclass functionality. 178 179 00:15:37,310 --> 00:15:44,260 So if all of that makes sense, then it's time for your next challenge. 179 180 00:15:44,510 --> 00:15:51,440 And that is, of course, the fact that we have a TodoListViewController which is also going to now 180 181 00:15:51,440 --> 00:15:57,460 subclass the SwipeTableViewController, instead of a 181 182 00:15:57,470 --> 00:15:58,760 UITableViewContnroller. 182 183 00:15:58,760 --> 00:16:05,860 So the challenge is for you to implement that swipe cell functionality inside the TodoListViewController, 183 184 00:16:06,350 --> 00:16:12,920 and you will need to understand subclassing, superclassing, and all of the things that we've done over 184 185 00:16:12,920 --> 00:16:13,660 here 185 186 00:16:13,910 --> 00:16:21,590 in order to make it work and complete the challenge. If you need, it might be worth reviewing some of 186 187 00:16:21,590 --> 00:16:30,050 the lectures earlier on where we talked about objects, classes, inheritance, and having a look at the steps 187 188 00:16:30,050 --> 00:16:38,300 that we went through to update our CategoryViewController to be a subclass of SwipeTableViewController. 188 189 00:16:38,450 --> 00:16:44,480 But this is quite challenging and I suspect that it might take you a little while to figure everything 189 190 00:16:44,480 --> 00:16:51,140 out. But if you do get it right, then you'll know for sure that all of these concepts made sense to you. 190 191 00:16:51,170 --> 00:16:56,820 So rather than proving it to anyone else, prove it to yourself that you've understood everything. 191 192 00:16:57,050 --> 00:17:01,910 So go forth and struggle, and I will see you on the other side.