 Hello and welcome back to another Code Pro lesson. Searching is a common feature in just about every app these days and knowing how to implement some basic search functionality is a required skill to be a mobile app developer. In this lesson, we're going to take a look at how to use the UI search controller to implement some basic search functionality that you can take advantage of in your iOS app. Let's open up Xcode and get started. So what we're going to make in this lesson is going to be something like this. We're going to implement a fuzzy search using a search controller. And starting off, we have this table view of a bunch of tech products, Apple Watch, iMac, Samsung Galaxy S10, different iPhones, iPads, MacBooks. And as we start to search for things, we're going to start to drill down to certain things we're searching for, such as Mac, we'll give you Mac and MacBook. We can say, let's say Dell gives us back some Dell XPSs that are in our data source, Apple Watch, maybe number two, which starts to filter down anything with two or 20 in there. And so we're going to see that this is really simple to implement using the search controller with really a little over 100 lines of code, if even that. And so let's get started by going into our interface builder and our main storyboard and getting our UI elements set up. There used to be an older search API that you could use. And in my storyboard here, if I go and I go into search and I type in search, I'll see that I have a search bar and a search bar and search display controller. Now let's say I drag this controller onto my main view controller. And you'll see here that I have a search display controller. And let's assume I try to make an IB outlet to it in the view controller. And we'll just call this search controller and hit command B to build the project. And you'll see that right away we're getting a warning message. And UI search display controller was deprecated in iOS 8, replaced with UI search controller. And so that you go back into your storyboard, right? And you look for UI search controller and nothing comes up. And so what we have to do for this is create it programmatically. Now you can still use the deprecated API if you want to, but this tutorial is going to be specifically on how to use the UI search controller. So let's go and drag a table view onto our view controllers view. So we can look for table view. You can drag one of these on. And let's also look for a UI view that's going to serve as the container view for our search bar. And I think I got to delete the search bar from before that I had there. And on our view, I'm going to go ahead and give this a different background color just so we can differentiate it from the rest of our view here. So go ahead and just kind of position this towards the top and give that a height of about maybe, I think 60 should be fine. For our table view, we'll position that right below. Drag that down, drag across here. I'm going to bring that flush to the edge. And touching the top of our container view there. And below our table view, we're going to create a button. And this button is just going to be a way to restore our data back to an original state if we want to do some more searching. And we can just call this restore data in the text. And we'll just bring our table view right down to it. And now we just need one more thing. We need a UI table view cell and we can drag that right onto our table view here. And now let's go ahead and set up our constraints and the cell reuse identifier starting with the search container bar at the top here. I'm going to actually drop this down to 50 height, which will be enough to hold the search bar just fine. For the auto layout constraints, what I'm going to do is a top, a leading, a trailing, and a bottom. I'm going to also do a fixed height constraint of 50 here and establish those. And I'm going to just slide the table view right up so it's flush to the edge there. As close as we can get it. And on the table view, I'm going to give it a top, a leading, a trailing, and a bottom here. And I'm just going to drag that bottom a little bit closer to the margins of the restore data button. And for the restore data button, I'm going to give it a bottom constraint. And over here, a horizontal in center or in container constraint like that. And I'm just going to fix my constraints here, see if I can bring this up and then update the constants to get rid of those warnings there. So constraints are good. Now we want to select the table view cell, go over to the attribute inspector, and I'm just going to give my reuse identifier of cell. And lastly, let's go ahead and create the IB outlets for these elements. So what I need to do is starting with this container view here, I'm going to control click and drag. We'll just call this search container view to our view controller. We'll do the same for the table view, control click and drag, table view outlet. And lastly, our restore data button, we're just going to create an IB action. So holding down the control key, click and drag. We'll just call this restore data. So our user interface is good to go. Now let's go ahead and start writing the implementation of the UI search controller. We're going to start off with a couple of properties first. The first one's going to be our search controller. So we can just call this var search controller. And it's a type of UI search controller. And I'm going to mark this as an implicit optional with the exclamation mark here. The next property we need is our data source or what we're going to call our original data source. And in this example, it's just nothing more than a collection of strings. So it's pretty simple. And it's going to look like this var original data source, and we'll initialize that to an empty collection. And then we're going to keep another property called var current data source, a collection of strings, and it too is going to be initialized empty here. And let's go down into our view did load method here and start setting up our search controller. For the search controller, we're going to do search controller equals UI search controller. And you'll see that we have a couple of options here. We have an initializer for a search results controller that says we can give it a particular view controller, but it's optional. And this is the one we're going to use. And we're going to pass in nil. And let's take a look at the documentation to understand this a little bit better. Looking through the documentation for that initializer we used, we can see that if we pass nil, if you wish to display the search results in the same view controller that you are searching in. So you have an option of giving another view controller to be the search results controller. In this example, and in this tutorial, we're going to assume that our view controller is going to be the view controller that does the searching and gets back the results. If you want a separate search results controller, well, then you'll need to pass that in here in the initializer. But searching through here a little bit more, we have a couple of the properties that are interesting. We have a UI search controller delegate. We have a property for the dims background during presentation. And there's an obscures background during presentation. There's a search bar, which is important. So we have access to a search bar on the search controller. And there's a protocol called UI search results updating that gives you basically live updates for searches that come into the search controller. So these are all things we need to be aware of and have some understanding of as we're going to use the UI search controller. Now let's go back over to our view controller. And right below here, what we'll do is search controller that search results updater is going to be equal to self. And so what we're saying is that we're going to have this view controller conform to the search results updater protocol so that it gets updates for searches as they come in. Now we have to make that, we have to conform here. So what we'll do is create an extension on view controller that conforms to UI search results updating and is going to implement the required method of update search results. And if we look at this protocol, we see that it gives us back the search controller in here. So we have access to the search bar, the search text, anything that was searched for from the local controller that was passed in to the protocol method here. Now what we'll do is go back and search container view dot add sub view search controller dot search bar. And so that that's going to put our search bar inside of our container. And what we can then do is search controller dot search bar dot delegate equals self. And so what we're going to do here is have our view controller be the delegate for the search bar event. So that gives us more flexibility for determining what we want to do for processing a search, clearing a search, so on and so forth. So we'll create another extension here on view controller. And that's going to conform to the UI search bar delegate protocol here. And in the search bar delegate, we can implement the search bar search button clicked. And we can implement the search bar cancel button clicked as well. Lastly, there's one other property here, we want to implement search controller that obscures background during presentation set defaults. But comment this out for right now. And what we're going to do is see what it does with this commented out. And then we're going to go ahead and uncomment this line of code and see the difference. We still need to do a little bit of work on our data source, particularly building our data source, setting up our table view delegate and data source. So we're going to work on that next. What we can do is create another function. And we're going to call this is add product to data source. We'll give it a product count and a product, which is going to be a string. We'll then loop through using the product count as how many products we want to add index and one through product count original data source that append a string in the string will be formatted like this product, then a number sign or a hashtag sign index, then to set up our data source, we can do is right before everything gets set up, we can do add product to data source. And let's say for example, this is 25. We want to add 25 MacBook pro 15 inch laptops like that. Then we can do add product to data source again. Let's say we want, I don't know, 20 MacBook airs like that. And maybe another one, maybe 30, just the MacBooks like that. And finally, at the very end, what we'll need to do is set the current data source equal to the original data source, because all of these are being appended to the original data source. And the current data source is going to really represent what we're currently looking at or viewing at that point in time as we're going through the search. The next function we need to write is the brains of the operation. It's going to be the function that actually takes a search term, and then filters out the current data source to a subset. And then basically assigns the current data source to that subset and reloads the table view. And what we'll do is we'll call this function filter current data source. And the parameter is going to be a search term, which is a string. The first thing we want to check for is that the search term is not an empty string. So we can do if search term that count is greater than zero, then go ahead and do the filter. The first thing we're going to do is assign the current data source is going to be equal to the original data source. So this lets us set it back to a fresh state, and then we can filter off of that fresh state down for the search term passed in. Otherwise, if we keep doing it on the same data source, we'll end up filtering it down to nothing eventually. So we want to reset it back to the original here. Now we're going to create another property, let filtered results equals current data source dot filter. What I'm going to do is do the shorthand syntax here. So it's going to look something like this, $0, which is going to represent the variables in the closure, which are just the strings. You can kind of think of it as like the left hand side or whatever element is being returned. And we're going to compare that against the search term here. And so how we're going to write that is going to look like this, dot replacing occurrences of any spaces with no spaces. We're going to make sure that we do a lower case on that. So that way we're catching things such as uppercase, lowercase, and we're kind of comparing apples to apples. And on top of that, we're going to append that with a dot contains search term dot replacing occurrences of a space with an empty string dot lowercase. Close the parentheses and then end the closure. Put that on a separate line is easier to read. Finally, current data source equals the filtered results. And we can top that off with a table view dot reload the data. And just to reiterate here, this is really the brains of the operation. If you don't necessarily care about comparing lowercase to lowercase and stripping out white spaces to put empty strings in for comparison, then you can manipulate this filter functionality as you see fit. But that's going to directly influence how your filtered results are going to appear when you assign them back to the current data source. And so this is just a quick and dirty, plain and simple way of doing a comparison, but you can do this however you feel fit. Next, we want to create a little function to restore our current data source to the original data source just so we can call it anywhere if we want to restore back to a starting state. So we can just do funk, restore current data source. And we'll just do a current data source equals original and table view that reload data. And that's all we'll need here. You'll notice it looks pretty similar to this, but we don't want to call it here because we don't want to assign it back to the original rather we want to assign the current data source to the filtered here. But in this function, we want to assign the current data source to the original and reload the data. We're almost done here. We need to go ahead and wire up our table view data source and delegate. So what we can do is go back to queued load just to table view dot delegate will set to self and table view that data source set to self. And we'll scroll down here and create an extension on view controller. And this is going to conform to the UI table view data source protocol and the UI table view delegate protocol like that. The three methods we need from here are going to be did select row at index path, the number of rows at section. And for number of rows in section, we're going to return the current data source dot count. Make sure you don't make the mistake of returning the original in here. We always want to be returning what is currently being displayed. And finally, we need to implement self a row at index path. And this is simple, just let cell equals table view dot dq reusable cell with identifier and index path cell dot text label dot text equals the current data source index that the index path dot row and just return the cell. And for did select row at index path, what we can do here is we're just going to create an alert controller that displays what we selected. So we can just see it. So let alert controller equals a UI alert controller. We'll give it a title of selection. The message will be selected. And we'll string format it like this. Current data source at index path dot row. So it's just going to basically put the string in for what we selected in there. We'll do a dot alert for the preferred style. We'll do a let okay action equals a UI alert action call it okay dot default for the style and no for the handler alert controller dot add action the okay action and finally present alert or present alert controller animated true. And the completion handler can be no. And there's one other thing we want to do in here and we'll explain it more once we start wiring up the final bits. But the search controller has a property dot is active. And anytime we're presenting the alert controller, we want to turn this defaults that way our alert controller can basically take precedence or it can have control of the window of the alert dialogue that's being presented. So we want to resign any search controller that might currently have focus right before we present our alert controller here. Now let's plug in the method calls for all of our different search entry points. So starting with the update search results method here, what we can do is if let search text equals a search controller dot search bar dot text filter current data source for the search term passing in search text like that for the search bar search button clicked will do a search controller dot is active equals false if let search text equals search bar dot text filter current data source for the search text and for the search bar cancel button clicked will do a search controller that is active equals false. And we're going to do a if let search bar or search text equals search bar dot text and search text that is empty is false or not empty restore current data source. And because for this check here the rationale behind it is when you're tapping the search bar maybe tap it accidentally but you don't enter any text and then you hit cancel. So we want to make sure we're not always resetting the current data source. If maybe you tapped it by accident but if you have searched text in the search bar then you've probably typed something and cancelling that action is going to restore the data back. Now let's go into the restore current data source method and you'll see we still have that button for the restore data that we added an interface builder and we can just have it make a call to restore current data source here. Now let's go ahead and test out everything we have. So here we go running the code and let's just start doing some searches. So we only have MacBooks as the products in here but if I do a search for let's say air I get back a list of only MacBook Airs. If I search for pro I should get back a list of only MacBook Pros but since we have so much data here it would be great if I could just search through here and I can't because if you remember from the beginning of this lesson we commented out this obscures background during presentation which right now is set to true. Now if we uncomment the line and run this again and let's say we do a search for pro you'll see that there's no window here that's taking over blocking us from scrolling so we can search through our entire list and verify that the only things in here should be MacBook Pros and if I do a click MacBook Pro 15 inch number 25 was selected if I do a click here MacBook Pro 15 inch number 19 selected if I do a restore we'll have everything back and you can scroll down and see the MacBooks the Airs the Pros and if I do a search for just MacBook maybe number starting with number two I'm starting to get back you know anything that follows the filtering criteria that we set so anything starting with number two 20 21 so on and so forth comes back and likewise searching for air returns MacBook Airs only in the data source and so that's a really simple way to set up the UI search controller there's a couple of parts to it but in reality we did this in 128 lines of code and it's relatively straightforward to implement the fuzzy search functionality using the search controller and that wraps up this lesson so hopefully now you have a general understanding of how to take advantage of the UI search controller and utilize it in your app to build in search functionality if you like this video you know what to do go ahead and smash that like button and consider subscribing to code pro just to have to date for all the lessons make sure to follow code pro on social media you can find me on twitter and on facebook and if you're looking for a full-length ios developers course make sure you check out my ios beginners course available on you can me and on skill share you can find links for that down below in the description and 50 off the course sign-up price also if you like the concept on this channel and you want to help me out you can support me on patreon and you can find that link down below in the description as well thank you so much for stopping by and i will catch you in the next one