0 1 00:00:00,750 --> 00:00:01,050 All right. 1 2 00:00:01,060 --> 00:00:06,320 So, so far we've looked at all four of the CRUD capabilities that Core Data offers. 2 3 00:00:06,390 --> 00:00:12,510 So we've looked at creating, reading, updating, and destroying data using the context, and once we're happy 3 4 00:00:12,510 --> 00:00:17,500 with our changes, then we've committed those changes to our persistent container. 4 5 00:00:17,820 --> 00:00:23,750 So, in this lesson, I want to talk about how you can query items using Core Data. 5 6 00:00:23,790 --> 00:00:29,970 So in order to do this, we're going to give our app a little bit more functionality, and the functionality 6 7 00:00:29,970 --> 00:00:35,580 that we want is having search capability, and adding that to our table view. 7 8 00:00:35,670 --> 00:00:42,480 So I want to be able to type in part of or completely a to-do list item. I want our table view to update 8 9 00:00:42,480 --> 00:00:46,500 to show me all of the items that are related with that searched him. 9 10 00:00:46,500 --> 00:00:52,510 So for example, I could have something like, you know, buy milk and buy eggs. 10 11 00:00:52,620 --> 00:00:56,140 and I just want to search for "buy" to see what I need to get from the supermarket. 11 12 00:00:56,400 --> 00:01:01,740 So in order to do that, we're going to go into our trusted object library and we're going to search for 12 13 00:01:02,220 --> 00:01:05,760 a search bar. A little bit circular there. 13 14 00:01:05,910 --> 00:01:11,430 But the one that we want is the Search Bar, not the Search Bar and Search Display controller because 14 15 00:01:11,430 --> 00:01:14,090 we're going to implement a really simple search bar. 15 16 00:01:14,190 --> 00:01:17,120 So I'm going to drag it on to our table view 16 17 00:01:17,220 --> 00:01:20,880 and I'm going to place it just below the navigation bar, 17 18 00:01:21,150 --> 00:01:23,170 so above the table view. 18 19 00:01:23,370 --> 00:01:29,040 So the next thing is to set our view controller as the delegate for the search bar, so that whenever there's 19 20 00:01:29,040 --> 00:01:34,590 any changes inside the search bar like, say, when somebody hits the search button, then this is the class 20 21 00:01:34,590 --> 00:01:35,780 that's going to be informed, 21 22 00:01:35,820 --> 00:01:40,510 and we're going to deal with whatever they type in there inside our TodoListViewController. 22 23 00:01:40,740 --> 00:01:46,330 So I'm going to say UISearchBarDelegate. 23 24 00:01:46,890 --> 00:01:52,080 Now, previously, every single time we've declared our view controller as a delegate of something. We also have 24 25 00:01:52,080 --> 00:01:57,930 to make an IBOutlet for our search bar. And then inside viewDidLoad, say something like searchBar.delegate 25 26 00:01:57,960 --> 00:01:58,770 = self. 26 27 00:01:58,770 --> 00:02:04,830 So we're familiar with these two steps, adding the protocol in the class declaration, and also setting 27 28 00:02:04,830 --> 00:02:07,280 the outlet's delegate as self. 28 29 00:02:07,340 --> 00:02:12,830 Now, this is optional, so you can either do it in code or 29 30 00:02:12,870 --> 00:02:20,040 the alternative is you can simply hit control, drag, and point to this little yellow icon which represents 30 31 00:02:20,130 --> 00:02:21,220 the view controller. 31 32 00:02:21,330 --> 00:02:27,450 And if you let go, you see that there is a delegate for this outlet that you can set as the view controller 32 33 00:02:27,720 --> 00:02:30,200 which, remember, the yellow icon represents. 33 34 00:02:30,220 --> 00:02:34,950 So make sure that you actually originat it from the search bar, rather than from somewhere else like, 34 35 00:02:34,950 --> 00:02:36,550 say, the table view, right? 35 36 00:02:36,600 --> 00:02:40,770 Because in this case, it's got a data source and delegate, and you can see that they're already set up 36 37 00:02:41,610 --> 00:02:42,350 to be 37 38 00:02:42,390 --> 00:02:42,750 our 38 39 00:02:42,780 --> 00:02:43,910 View Controller class. 39 40 00:02:44,100 --> 00:02:51,780 So it might even be easier going from the document outline and dragging it to the yellow icon, and then 40 41 00:02:51,780 --> 00:02:53,150 hitting delegate. 41 42 00:02:53,190 --> 00:02:58,590 So the next step if we go back into our TodoListViewController is we need to add some delegate methods 42 43 00:02:58,950 --> 00:03:02,160 in order to make the UISearchBarDelegate work, right? 43 44 00:03:02,160 --> 00:03:08,580 So what we can do is right at the bottom below loadItems, we can add the delegate method and it's called 44 45 00:03:08,620 --> 00:03:11,570 a searchBar. 45 46 00:03:11,640 --> 00:03:18,420 Usually, so for a lot of these methods, as long as you're aware they exist, you can pretty much guess what you 46 47 00:03:18,420 --> 00:03:24,360 should start typing in order to get this list of suggestions come up. And you can scroll through them 47 48 00:03:24,390 --> 00:03:28,770 looking at the information texts as to what each one does 48 49 00:03:29,040 --> 00:03:36,300 until you find the one that you want which is, in my case, searchBarSearchButtonClicked. 49 50 00:03:36,420 --> 00:03:41,790 So this tells a delegate that the search button was tapped and that is the point where we want to reload 50 51 00:03:41,790 --> 00:03:45,800 our table view using the text that the user has inputted. 51 52 00:03:46,050 --> 00:03:49,870 So let's hit enter and insert that delegate function in there. 52 53 00:03:49,890 --> 00:03:55,490 Now, some of you might wonder if we have so many of these delegates saying, you know, we have 53 54 00:03:55,500 --> 00:04:02,400 UISearchBarDelegate, then at a later stage, we decide to add like a picker view, UIPickerViewDelegate, then we 54 55 00:04:02,460 --> 00:04:07,680 ddecide to have one which is UIImagePickerControllerDelegate. 55 56 00:04:07,710 --> 00:04:13,700 If we have all of these stacking up because we need all of them in our app inside the same view controller, 56 57 00:04:13,710 --> 00:04:17,490 inside the same screen, then it's going to start getting pretty cramped up here. 57 58 00:04:17,670 --> 00:04:24,110 And you've also got different delegate methods that relate to each of these bits of functionality, 58 59 00:04:24,120 --> 00:04:28,390 for example, the SearchBar or the PickerView, ImagePickerController. 59 60 00:04:28,620 --> 00:04:32,080 And should they really all be crammed into the same class? 60 61 00:04:32,100 --> 00:04:35,490 I mean, it seems like it's going to get a little bit tight on space, right? 61 62 00:04:35,640 --> 00:04:40,710 Well, the alternative that we can use that you're going to see in a lot of projects that you download from 62 63 00:04:40,710 --> 00:04:47,100 GitHub, or out there in the wild, is this is the closing brace for our class and everything inside is our 63 64 00:04:47,100 --> 00:04:49,440 TodoListViewController class. 64 65 00:04:49,440 --> 00:05:00,430 Now, if we go outside of the last curly brace and we create an extension, then we can extend the functionality 65 66 00:05:00,880 --> 00:05:09,260 of our TodoListViewController, and we can set it to be a UISearchBarDelegate. 66 67 00:05:09,640 --> 00:05:16,900 So the advantage of this is that we can split up the functionality of our view controller and we can have 67 68 00:05:17,170 --> 00:05:20,560 specific parts that are responsible for specific things. 68 69 00:05:20,560 --> 00:05:27,790 So for example, this extension extends our base view controller and gives it the extra power or the extra 69 70 00:05:27,790 --> 00:05:31,240 functionality of being able to handle search bar methods. 70 71 00:05:31,360 --> 00:05:36,840 So the other advantage is that when you look up here, you can see that we've got the base class here 71 72 00:05:36,910 --> 00:05:39,160 and we've got our extension down here. 72 73 00:05:39,280 --> 00:05:45,610 And one of the downsides of MVC or the model-view-controller pattern that Apple is such a big fan of 73 74 00:05:45,940 --> 00:05:53,780 is that your C starts getting really, really big, and it basically becomes like tiny "M," tiny "V," and massive 74 75 00:05:53,790 --> 00:06:00,580 "C." You often see these gigantic view controllers, especially when you look at Apple's example projects, 75 76 00:06:00,850 --> 00:06:02,560 and they just start getting really, really big. 76 77 00:06:02,560 --> 00:06:09,830 So it's really important that you modularize and try to split up the functionality as much as you can, 77 78 00:06:09,940 --> 00:06:15,580 not just for code organization, which is handy, but also so that when you come to debug it, you can narrow 78 79 00:06:15,580 --> 00:06:20,580 down on which section you need to look at, instead of going through the entire page, right? 79 80 00:06:20,980 --> 00:06:28,510 So for example, if we had issues with our search bar, then we can navigate straight down to our extension 80 81 00:06:28,540 --> 00:06:34,000 that deals with all of the search bar functionality, and we can read only, you know, maybe 10 lines, rather 81 82 00:06:34,000 --> 00:06:35,620 than 100 lines of the page. 82 83 00:06:35,620 --> 00:06:42,910 So, so far we've been using these MARK comments in order to be able to look at our view controller and 83 84 00:06:42,910 --> 00:06:49,290 have this quick breakdown of what are the different sections, and what are the methods in each section. 84 85 00:06:49,450 --> 00:06:55,840 But now we have this extension, and even though the extension, unfortunately, doesn't allow you to rename 85 86 00:06:55,840 --> 00:07:03,480 it, you can still put a MARK above it so that you can see it as a separate section. 86 87 00:07:03,490 --> 00:07:14,470 So we'll call this "Search bar methods." And when we go into our file now, we can see our main class, 87 88 00:07:14,470 --> 00:07:19,000 as well as our extension class which is responsible for the search bar methods. 88 89 00:07:19,000 --> 00:07:26,380 So this is a very Swifty kind of pattern and you're going to see this pretty much everywhere. And usually 89 90 00:07:26,380 --> 00:07:32,800 as a rule of thumb, whenever I want to create a new protocol here in the class declaration line, 90 91 00:07:32,800 --> 00:07:39,440 I tend to create a new extension and group the protocol methods together, like we're going to do now. 91 92 00:07:39,490 --> 00:07:47,380 So inside our TodoListViewController extension where we are extending the functionality with a search 92 93 00:07:47,380 --> 00:07:53,620 bar and some search bar methods, we've got this delegate method which is going to be triggered once the 93 94 00:07:53,620 --> 00:07:56,530 user presses the search button on the search bar. 94 95 00:07:56,530 --> 00:08:02,740 So this is a good point for us to query our database and try to get back the results that the user is 95 96 00:08:02,740 --> 00:08:03,460 searching for. 96 97 00:08:03,460 --> 00:08:09,140 So as always, in order to read from the context, we always have to create a request and we have to declare 97 98 00:08:09,140 --> 00:08:10,830 the request data type. 98 99 00:08:10,830 --> 00:08:19,550 So NSFetchRequest and it's going to return an array of items, and we're going to set this to equal 99 100 00:08:20,480 --> 00:08:23,190 Item.fetchRequest. 100 101 00:08:23,210 --> 00:08:30,740 Now, the next step is we have to specify what is going to be our filter, right? What is going to be our 101 102 00:08:30,740 --> 00:08:31,830 query? 102 103 00:08:32,090 --> 00:08:35,510 And we do that using something called an NSPredicate. 103 104 00:08:35,570 --> 00:08:41,750 But before we do that, let's first have a look at what is the data that we get back when the user clicks 104 105 00:08:41,750 --> 00:08:43,720 on the search button in the search bar. 105 106 00:08:43,910 --> 00:08:52,650 So let's go ahead and just print out the searchBar.text, and let's go ahead and run our app. 106 107 00:08:52,670 --> 00:08:53,000 All right. 107 108 00:08:53,000 --> 00:08:56,160 So the first thing that we see is that we now have a search bar. 108 109 00:08:56,300 --> 00:08:58,570 Yay! That was pretty easy, right? 109 110 00:08:58,610 --> 00:09:06,290 And the first thing I'm going to do is I'm going to hit command K or go to Hardware, and keyboard, and 110 111 00:09:06,350 --> 00:09:11,180 Toggle Software Keyboard. So command K does exactly the same thing and it basically pops up and pops 111 112 00:09:11,180 --> 00:09:19,940 down the keyboard on screen, and then I'm going to, for example, type "Save" in order to pull up all the 112 113 00:09:19,940 --> 00:09:26,570 items that contain the words "Save," either in their title, and then I'm going to hit search. And this is 113 114 00:09:26,570 --> 00:09:32,750 the point where our searchBarSearchButtonClicked delegate method gets fired and it runs everything 114 115 00:09:32,750 --> 00:09:33,790 that's inside. 115 116 00:09:33,830 --> 00:09:39,800 And so our print statement prints out what the searchBar.text! at this point is, and it's the word that 116 117 00:09:39,800 --> 00:09:41,420 we entered which is "Save." 117 118 00:09:41,720 --> 00:09:44,540 Okay, so that worked pretty nicely. 118 119 00:09:44,700 --> 00:09:49,580 It's always a good idea to check along the way to make sure that all your presumptions are right and all 119 120 00:09:49,580 --> 00:09:54,520 your setup, especially with these UIElements have not gone awry. 120 121 00:09:54,710 --> 00:10:02,930 So we now have this request and we need to modify it so that we tag on a query that specifies what we 121 122 00:10:02,930 --> 00:10:05,510 want to get back from the database. 122 123 00:10:05,510 --> 00:10:11,930 So in order to query objects using Core Data, we need to use something called an NSPredicate. 123 124 00:10:11,930 --> 00:10:19,700 So we can say, for example, let predicate = NSPredicate and we're going to initialize it using 124 125 00:10:19,760 --> 00:10:21,050 a format. 125 126 00:10:21,050 --> 00:10:27,410 So the format, as you can see from the placeholder, takes a string and the string is a little bit scary 126 127 00:10:27,410 --> 00:10:33,440 because you're now typing in free text. And in our case, what we would do is we would say "title," 127 128 00:10:33,440 --> 00:10:38,290 we're going to look at the title attribute of each of our items in our itemArray, 128 129 00:10:38,630 --> 00:10:42,510 and we're going to check that it CONTAINS a value. 129 130 00:10:42,620 --> 00:10:49,410 So this is the argument that we're going to substitute into this percentage, "at" sign. 130 131 00:10:49,520 --> 00:10:54,350 And I'm going to talk about why all of this looks so different from what we've been doing in Swift in just 131 132 00:10:54,350 --> 00:11:00,860 a moment, but let's just set it up first. And the argument is, of course, what we printed out in our print 132 133 00:11:00,860 --> 00:11:04,850 statement which is the searchBar.text. 133 134 00:11:04,850 --> 00:11:12,080 And so when we hit the search button, then whatever we have entered inside the searcBar at that time 134 135 00:11:12,080 --> 00:11:19,880 point is going to be passed in to this method into this part, and replacing this percentage, "at" sign. 135 136 00:11:20,120 --> 00:11:27,140 So then our query becomes "For all the items in the item array, look for the ones where the title of the 136 137 00:11:27,140 --> 00:11:30,230 item contains this text." 137 138 00:11:30,230 --> 00:11:36,410 So this is pretty unfamiliar if you have only been working with Swift. 138 139 00:11:36,410 --> 00:11:42,310 This part might look quite familiar to you if you've ever used or looked at Objective-C code. 139 140 00:11:42,440 --> 00:11:49,310 And the reason is because NSPredicate is basically a foundation class that specifies how data should 140 141 00:11:49,310 --> 00:11:55,560 be fetched or filtered. It's essentially a query language which is like some sort of weird lovechild 141 142 00:11:55,610 --> 00:12:02,390 between the SQL WHERE clause and a rejects or regular expression. It's meant to be similar to natural 142 143 00:12:02,390 --> 00:12:05,920 language like how you would speak in English. 143 144 00:12:06,080 --> 00:12:13,250 But there's a whole bunch of modifiers and logical conditions that you have access to that you can put 144 145 00:12:13,250 --> 00:12:15,440 inside this format string. 145 146 00:12:15,650 --> 00:12:17,990 So let's take a look at those. 146 147 00:12:18,140 --> 00:12:24,590 So a really good resource is actually on the Realm blog, and even though we're not using Realm yet, we're 147 148 00:12:24,590 --> 00:12:26,300 actually still using Core Data. 148 149 00:12:26,300 --> 00:12:31,710 When you query items inside Realm, they also use the same thing which is NSPredicate. 149 150 00:12:31,760 --> 00:12:38,390 So they've made this beautiful PDF that is, essentially, NSPredicate Cheatsheet which you can download 150 151 00:12:38,450 --> 00:12:42,100 from this link here which I'll include in the resources for this lesson. 151 152 00:12:42,090 --> 00:12:45,310 But, essentially, you can have a look at how the string is structured, 152 153 00:12:45,440 --> 00:12:45,680 right? 153 154 00:12:45,680 --> 00:12:51,650 So remember that the percentage "at" sign substitutes any sort of argument that you want to pass in, and 154 155 00:12:51,650 --> 00:12:57,230 you can use most of your basic comparisons like left hand is equal to right hand, or left hand is greater 155 156 00:12:57,230 --> 00:13:02,940 than or equal to the right hand, as well as everything that we've been using so far. 156 157 00:13:03,080 --> 00:13:05,680 But it's also got some of these special words in all caps. 157 158 00:13:05,690 --> 00:13:11,780 For example, the word like "BETWEEN," right? The left hand expression is BETWEEN or equal to the right hand 158 159 00:13:11,780 --> 00:13:13,490 expression. 159 160 00:13:13,760 --> 00:13:16,600 And you can compound your predicates together 160 161 00:13:16,770 --> 00:13:26,820 by using the "AND," "OR," and "NOT." So you can say that the age is equal to 40 AND the price is greater than 67. 161 162 00:13:26,850 --> 00:13:34,350 I don't know in which case you love to look for something that has age over 40 and price over 162 163 00:13:34,430 --> 00:13:38,280 67. Well, maybe wines, I guess. That works. 163 164 00:13:38,520 --> 00:13:41,320 I don't know why I was thinking about humans or pets. 164 165 00:13:41,380 --> 00:13:44,160 That's really bizarre. Anyways-- 165 166 00:13:44,790 --> 00:13:50,730 So it's also got things like string comparison operators which is what we use which is the "CONTAINS" 166 167 00:13:51,030 --> 00:13:58,530 because our title is a string and we want to check to make sure that the titles of each of those items 167 168 00:13:58,710 --> 00:14:04,680 contains, i.e., it can partly contain the text that we're searching for, because we're not going to enter 168 169 00:14:04,710 --> 00:14:07,650 the exact word that we're looking for. 169 170 00:14:07,740 --> 00:14:12,630 If we're looking to try and pull up the items like "buy milk," and "buy bread," then it's not very useful 170 171 00:14:12,630 --> 00:14:14,160 just searching for "buy milk," 171 172 00:14:14,200 --> 00:14:15,720 so that "buy milk" pops up, right? 172 173 00:14:15,770 --> 00:14:18,760 We want to look at all the things that contains the word "buy." 173 174 00:14:18,960 --> 00:14:24,840 Now, if you wanted an exact match, then you might use something like "MATCHES," right? so that it exactly 174 175 00:14:24,870 --> 00:14:26,420 equals the right-hand side. 175 176 00:14:26,430 --> 00:14:30,750 So when you're dealing with strings, then these are some good ones to work with. 176 177 00:14:30,880 --> 00:14:36,330 For all the other data types, then usually you'd be using these basic comparatives when you're working 177 178 00:14:36,330 --> 00:14:37,970 with numbers especially. 178 179 00:14:38,040 --> 00:14:40,030 So this is a brilliant Cheatsheet. 179 180 00:14:40,050 --> 00:14:41,490 Have a look at it. Study it 180 181 00:14:41,490 --> 00:14:46,620 if you're going to be querying a database. And you can do a lot of really sophisticated stuff with it 181 182 00:14:47,160 --> 00:14:50,400 and it's still relatively short and easily readable. 182 183 00:14:50,400 --> 00:14:54,750 And they've also got some tips, tricks, and examples which work with Core Data as well. 183 184 00:14:54,750 --> 00:15:00,630 It's basically how you search your databases using Realm or using Core Data. 184 185 00:15:01,080 --> 00:15:03,270 And another good article is this one on 185 186 00:15:03,270 --> 00:15:08,970 NSPredicate written by Mattt Thompson who was one of the creators of Alamofire that we've been 186 187 00:15:08,970 --> 00:15:09,690 using so far. 187 188 00:15:09,720 --> 00:15:11,490 So a really good article on this 188 189 00:15:11,490 --> 00:15:13,100 if you want to read out more on it. 189 190 00:15:13,200 --> 00:15:17,970 And one of the things you need to remember about string comparisons using NSPredicate, as you'll 190 191 00:15:17,970 --> 00:15:24,180 find in this article, is that string comparisons are by default case and diacritic sensitive. 191 192 00:15:24,240 --> 00:15:30,450 So case, obviously, means upper-lower case, and diacritic refers to these little marks above your letters. 192 193 00:15:30,450 --> 00:15:37,470 So, for example, in French, you have the "circonflexe" and the "grave" accents, or in German, you have the "umlaut." 193 194 00:15:37,470 --> 00:15:43,530 So these are the diacritics. And you know for us to implement search, do we really want it to be case-sensitive 194 195 00:15:43,530 --> 00:15:44,750 and diacritic-sensitive? 195 196 00:15:44,760 --> 00:15:45,510 Probably not. 196 197 00:15:45,600 --> 00:15:51,630 So you can modify that by just adding the square brackets and including "c" and "d." So "c" stands for case 197 198 00:15:51,630 --> 00:15:57,190 and "d" stands for diacritic, and it makes it, basically, insensitive to these two things. 198 199 00:15:57,270 --> 00:16:03,820 So let's go back to our code and modify it with our new knowledge. So we can add it after the "CONTAINS" 199 200 00:16:03,830 --> 00:16:05,510 And we're just going to add "CD" to it. 200 201 00:16:05,670 --> 00:16:11,470 So, now we have structured our query and we're going to add our query to our request, so we can say 201 202 00:16:11,470 --> 00:16:14,580 request.predicate = predicate. 202 203 00:16:14,590 --> 00:16:21,450 All right, so now that we've created our predicate which specifies how we want to query our database, 203 204 00:16:21,780 --> 00:16:27,210 the next thing that we can do is we can actually sort the data that we get back from the database in 204 205 00:16:27,300 --> 00:16:28,550 any order of our choice. 205 206 00:16:28,770 --> 00:16:38,100 So we can create a sortDescriptor that is a NSSortDescriptor, and we can say that we want to sort 206 207 00:16:38,100 --> 00:16:46,110 using the key that's the titles of each of the Items, and we can sort it in alphabetical order by saying 207 208 00:16:46,210 --> 00:16:47,610 ascending equals true. 208 209 00:16:47,670 --> 00:16:56,280 So, now we can add the sortDescriptor to our request by saying request.sortDescriptor, so it's really 209 210 00:16:56,280 --> 00:17:02,490 important that you notice here that this property is actually plural and that's because it expects an 210 211 00:17:02,490 --> 00:17:04,650 array of NSSortDescriptors. 211 212 00:17:04,650 --> 00:17:08,540 But in our case, we actually just want to specify a single sort rule. 212 213 00:17:08,610 --> 00:17:13,950 So we're going to say sortDescriptors equals an array of sortDescriptors, but it only contains a single 213 214 00:17:13,950 --> 00:17:16,770 item and that's a perfectly valid code. 214 215 00:17:17,100 --> 00:17:22,650 So, now all we have to do is to run our request and fetch the results, right? 215 216 00:17:22,830 --> 00:17:28,050 So if you have a look in our loadItems method, you can see that we've got a block of code that does 216 217 00:17:28,140 --> 00:17:29,530 exactly that. 217 218 00:17:29,550 --> 00:17:39,750 So we can copy and paste it over here so that we can try using our context to fetch these results from 218 219 00:17:39,750 --> 00:17:40,920 our persistent store 219 220 00:17:40,920 --> 00:17:47,190 that satisfy the rules that we specified for our request which is, namely, the title should contain 220 221 00:17:47,250 --> 00:17:54,570 whatever is in the searchBar, and the results should come back with their titles assorted in ascending 221 222 00:17:54,600 --> 00:17:55,570 alphabetical order. 222 223 00:17:55,650 --> 00:18:03,540 So then we assigned the results of that fetch to our itemArray and we now need to reload our 223 224 00:18:03,540 --> 00:18:10,290 tableView so that we retrigger the cellForRowAt indexPath methods and we update our tableView with the 224 225 00:18:10,320 --> 00:18:13,920 current itemArray which contains the results of the search. 225 226 00:18:13,920 --> 00:18:19,890 So, now as I always say, whenever you find yourself copying and pasting large chunks of code, then it's 226 227 00:18:19,890 --> 00:18:25,470 probably a good trigger for you to think about whether if you can refactor your code so that it's more 227 228 00:18:25,470 --> 00:18:26,040 succinct 228 229 00:18:26,250 --> 00:18:30,340 and you're not repeating yourself, but instead keeping all code dry. 229 230 00:18:30,450 --> 00:18:36,750 But before you refactor your code, you should always make sure that you test your assumptions and make 230 231 00:18:36,750 --> 00:18:39,090 sure that the current code works. 231 232 00:18:39,180 --> 00:18:44,510 So let's do that now. Let's run our app and see if it works. 232 233 00:18:44,520 --> 00:18:44,820 All right. 233 234 00:18:44,820 --> 00:18:49,810 So I've added a whole bunch of items that all contain the word "Save." 234 235 00:18:49,980 --> 00:18:54,120 So there's four items that contain a capitalized Save. 235 236 00:18:54,190 --> 00:18:58,360 There's one lowercase save and this one save with a diacritic. 236 237 00:18:58,620 --> 00:19:06,210 So if we go into our search bar and search for the word "Save" with a capital "S," we're going to look inside 237 238 00:19:06,240 --> 00:19:11,480 all of these items and look for the ones that contain the word "Save," 238 239 00:19:11,550 --> 00:19:15,490 and our query is case and diacritic insensitive. 239 240 00:19:15,780 --> 00:19:18,240 So let's go ahead and hit search. 240 241 00:19:18,240 --> 00:19:24,870 Which, of course, triggers the searchBarSearchButtonClicked delegate method and executes all of this 241 242 00:19:24,870 --> 00:19:25,470 code. 242 243 00:19:25,650 --> 00:19:33,240 And when we get back, there's all of the items that contain the word "Save" and it's case and diacritic insensitive. 243 244 00:19:33,240 --> 00:19:38,510 So, now that we've proven that our code works, then it's a good time to refactor our code. 244 245 00:19:38,730 --> 00:19:42,700 So one of the first things is that we probably don't need this constant, 245 246 00:19:42,840 --> 00:19:43,130 right? 246 247 00:19:43,140 --> 00:19:46,830 We can simply replace it with request.predicate 247 248 00:19:50,470 --> 00:19:58,560 and we can delete this line. So two become one. And we can replace this let sortDescriptor with 248 249 00:19:58,710 --> 00:20:00,250 request.sortDescriptor. 249 250 00:20:00,450 --> 00:20:06,670 Now, before we can delete this line, we have to realize that sortDescriptors expects an array of 250 251 00:20:06,710 --> 00:20:07,340 NSSortDescriptors. 251 252 00:20:07,500 --> 00:20:14,280 So we have to add these square brackets around this line on the right-hand side in order to make it equivalent 252 253 00:20:14,610 --> 00:20:15,740 to this. 253 254 00:20:15,840 --> 00:20:18,070 And now we can finally delete that line. 254 255 00:20:18,300 --> 00:20:20,840 So, now we've gone down from four to two. 255 256 00:20:21,030 --> 00:20:28,370 And finally, as I said before, we've got this do-catch block that's repeated inside our loadItems method. 256 257 00:20:28,650 --> 00:20:35,740 So I want to be able to call loadItem, rather than having to write out all of this code again. 257 258 00:20:35,760 --> 00:20:44,340 So what I can do is I can comment out this code and I can modify this function to take a parameter that 258 259 00:20:44,400 --> 00:20:46,310 is the request. 259 260 00:20:46,350 --> 00:20:55,080 So this is going to be of data type NSFetchRequest and it's going to return an array of Items. 260 261 00:20:55,080 --> 00:21:02,070 So, now instead of repeating this do-catch block, I can simply say loadItems and the request I want to 261 262 00:21:02,070 --> 00:21:08,080 make is this modified request which contains the query and the sort descriptors. 262 263 00:21:08,340 --> 00:21:13,880 So I can say loadItems with request and the request is this one. 263 264 00:21:13,950 --> 00:21:22,020 So the only problem here is that loadItems(request request) doesn't really make a lot of sense in English, 264 265 00:21:22,020 --> 00:21:22,740 right? 265 266 00:21:22,830 --> 00:21:27,660 And what you notice with Swift is that it's really pro-natural language. 266 267 00:21:27,660 --> 00:21:32,560 So you want to have your method calls sound almost like they make sense in English. 267 268 00:21:32,610 --> 00:21:37,750 So having "request: request" is kind of confusing and doesn't make a lot of sense. 268 269 00:21:37,860 --> 00:21:43,110 So we can modify this parameter to also have an external parameter. 269 270 00:21:43,110 --> 00:21:46,900 So this is the external parameter and this is the internal parameter. 270 271 00:21:47,130 --> 00:21:54,600 So the internal parameter is going to be used inside this block of code and the external one is the one 271 272 00:21:54,600 --> 00:21:56,770 that we're going to use when we call the function. 272 273 00:21:56,940 --> 00:21:58,560 So now that reads a little bit better, 273 274 00:21:58,590 --> 00:22:00,590 loadItems(with: request) 274 275 00:22:00,610 --> 00:22:05,130 Right? Now, what's happening is we're creating a new request, 275 276 00:22:05,130 --> 00:22:09,760 then we modify it with our query and our sortDescriptor, 276 277 00:22:10,050 --> 00:22:16,910 and then we pass that request into our loadItems function over here as NSFetchRequest. 277 278 00:22:16,980 --> 00:22:24,750 And then we perform that request by saying context.fetch. So we can now delete this do-catch block 278 279 00:22:24,840 --> 00:22:31,170 and we can also delete tableView.reload data because it's already inside loadItems, and we now have a 279 280 00:22:31,170 --> 00:22:34,460 shorter and much sweeter block of code. 280 281 00:22:34,530 --> 00:22:40,740 Now, because we're passing in the request, and then we're creating a new constant code request, 281 282 00:22:40,740 --> 00:22:41,910 it's a little bit confusing 282 283 00:22:41,910 --> 00:22:44,100 which one is used here. 283 284 00:22:44,250 --> 00:22:49,530 And in fact, we don't really need this line if we're going to pass in the request. 284 285 00:22:49,530 --> 00:22:52,340 We don't need to reinitialize a new request, 285 286 00:22:52,350 --> 00:22:58,740 right? Now, there's just one problem, and Xcode is actually notifying you of it using this little error here, 286 287 00:22:59,580 --> 00:23:06,660 and it's saying right at the beginning when we perform viewDiLoad, we also called loadItems, and this 287 288 00:23:06,660 --> 00:23:12,480 is where we want to load up all of the to-do list items from our persistent container. 288 289 00:23:12,480 --> 00:23:17,250 And at this point, we're not really interested in querying it or sorting it. We just want every single 289 290 00:23:17,250 --> 00:23:20,340 to-do list item so that we can show it in our table view. 290 291 00:23:20,370 --> 00:23:25,980 But now this loadItems method actually expects a parameter. 291 292 00:23:26,250 --> 00:23:27,840 So what can we do? 292 293 00:23:27,930 --> 00:23:36,210 Well, we could maybe copy this line of code and paste it up here, so we can say let request equals just 293 294 00:23:36,240 --> 00:23:42,230 fetch, all of the items from the persistent store, and we can now pass it in as a parameter, 294 295 00:23:42,240 --> 00:23:48,810 say loadItems with request. But this is not really ideal and it's not all that succinct either. 295 296 00:23:49,050 --> 00:23:58,090 So we can actually shorten this code even more by providing our parameter with a default value. 296 297 00:23:58,410 --> 00:24:05,200 So we can say that the request is of type and as fetch request which should fetch an array of items, 297 298 00:24:05,250 --> 00:24:12,420 that's the data type, and if when we call this function and we don't provide a value for the request, 298 299 00:24:12,810 --> 00:24:18,420 then we can have a default value that simply Item.fetchRrequest. 299 300 00:24:18,420 --> 00:24:26,850 So, now we can delete this line of code and we can be safe in knowing that when we call loadItems with 300 301 00:24:26,850 --> 00:24:33,220 request and we provide an argument, then that's the one that we're going to fetch from our context. 301 302 00:24:33,420 --> 00:24:41,880 But if we call on loadItems without a NSFetchRequest Item, then we can simply use the default value 302 303 00:24:41,910 --> 00:24:44,080 which is Item.FetchRequest. 303 304 00:24:44,220 --> 00:24:51,240 And what this allows us to do isup here when we call loadItems, we can simply call it as we did before 304 305 00:24:51,570 --> 00:24:56,560 without giving it any parameters, and we can also delete this line of code. 305 306 00:24:56,640 --> 00:25:03,810 So this method is a little bit complex because we have an external and an internal parameter, but, also, 306 307 00:25:04,050 --> 00:25:10,900 it has a default value in cases where we call loadItems without giving it any parameters. 307 308 00:25:11,070 --> 00:25:17,430 So it's a good idea to have a play around maybe in playgrounds at creating methods that have internal 308 309 00:25:17,550 --> 00:25:25,740 and external parameters just to see how it works, and also to create methods that have default values, 309 310 00:25:25,740 --> 00:25:29,240 so you can see how you can call them and how you can create them. 310 311 00:25:29,280 --> 00:25:35,910 Now, there's just one problem with our search bar and it's the fact that we can actually get back to 311 312 00:25:35,910 --> 00:25:37,510 our original table view. 312 313 00:25:37,590 --> 00:25:42,240 What do we do once we're satisfied with searching for the word "Save"? 313 314 00:25:42,450 --> 00:25:46,050 And we actually want to go back to seeing all of the to-do list items. 314 315 00:25:46,050 --> 00:25:51,460 It doesn't help if we try and click the cross and delete all the search, we can't get back, right? 315 316 00:25:51,470 --> 00:25:54,000 And that's because we haven't written any code to do that yet. 316 317 00:25:54,210 --> 00:25:56,760 So that's what we're going to do in the next lesson. 317 318 00:25:56,760 --> 00:26:02,700 We're going to address that bug and we're going to fix our table view so that we can return to our original 318 319 00:26:02,700 --> 00:26:03,770 state. 319 320 00:26:03,810 --> 00:26:06,470 So for all of that and more, I'll see you on the next lesson.