Search Bar Controller and Search Throttling
AppStore JSON APIs
Building search into your view controllers is rather simple in an iOS application. In this lesson, we'll be utilizing the UISearchController to add in a search bar at the top of our AppsSearchController. With this search bar now available, we can hook it up to our searching function inside of our Service layer. At the end of the lesson, I'll briefly go over throttling so that searches aren't executed so aggressively. This will be done using a Timer object which is pretty easy to set up.

Comments (22)
Viswa Kodela
4 years ago
Hey Brian, I think it would be nice if you fetch the data in the background thread and later reload the collection view once you receive all the appResults. That way we can reduce the load on the main thread.
Brian Voong
4 years ago
Viswa Kodela
4 years ago
Yeah, that make sense, don’t how i missed this. Thanks for the detailed response.
ayon
4 years ago
Hi brian just wanted to ask you that, what is the difference between using SearchResultUpdate and SearchBarDelegate
TWei
4 years ago
I think those two have different functions to override, but the result is the same which detects the text change of search bar. Correct me if I'm wrong
TWei
4 years ago
UISearchController seems like a new thing?
Brian Voong
4 years ago
Fusion Engineering
4 years ago
passing the searchTerm directly into URL string crashes the app if search term contains spaces. We need to encode it before creating the URL. I used searchTerm.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) to solve this issue. Is It the right way of solving this issue?
Brian Voong
4 years ago
TWei
4 years ago
Hi Brian, if we look at the original App Store app search functionality, when we start to type, a tableview shows up with the predictions. I'm thinking how could we achieve that? It is like we have two tableviews in the view controller, one for app cell, another one for prediction. When starts to type, predictionTableView.isHidden = false, kinda like that? Thanks
Brian Voong
4 years ago
TWei
4 years ago
Thanks boss
serxhio
4 years ago
This is my favorite video so far! Even though all content is great! I'm really happy I purchased this, will definitely apply these skills in my personal app! Thank you, Brian!
Janek Kruczkowski
4 years ago
Hi Brian, You have a bug inside your fetchApps method at Service.swift file. You should addingPercentEncoding to your searchTerm before you add this string to the URL. Now when user type for example space character like Uber Eats inside the search bar your method throws an error because of unencoded character and API call fails.
adam_rich
4 years ago
You didn't say how to code the get button to pull data from JSON
adam_rich
4 years ago
Also when searching a two or more word phrase you get an error ie: "facebook messenger" how do I correct this?
Brian Voong
4 years ago
adam_rich
4 years ago
I figured it out, for those who want to know put: let searchText = searchText.replacingOccurrences(of: " ", with: "+") in the search bar (..._textDidChange)
Anthony hordern
4 years ago
Love the video’s learn so much each time thanks heaps
stevenjemm
4 years ago
Just wanted to say thank you for this! Much of it I am well aware of but it helps to see how many other ways there are to do the same things! For the text on the empty state, you can also try creating an extension on the collectionView class to set its backgroundView: extension UICollectionView { func setupEmptyState(with message: String){ let enterSearchTermLabel: UILabel = { let label = UILabel() label.text = message label.textAlignment = .center label.font = UIFont.boldSystemFont(ofSize: 20) return label }() self.backgroundView = enterSearchTermLabel } func restore() { self.backgroundView = nil } } Calling that setEmptyState method if appResults.isEmpty and returning 0. Else set the backgroundView back to nil by calling the restore method and returning appResults.count I use this to include buttons etc as well since it takes a view and not just a label...found it somewhere through a stackoverflow thread some while back :) thanks again Brian!
Tokyojogo
4 years ago
stevenjemm, are you also calling this inside numberOfItemsInSection?
stevenjemm
4 years ago
Hey Tokyojogo, Yes I call it in numberOfItemsInSection basically as a check: If #yourArray.isEmpty { setupEmptyState(message: “some message”) return 0 } return #yourArray.count
stevenjemm
4 years ago
Just before return #yourArray.count Call restore() To set the backgroundView back to Nil
Tokyojogo
4 years ago
I tried this but when the cancel button is clicked or when the textfield moves up, its jarring how it moves up and down.
Jesus MH
4 years ago
Is a excellent course, i dont speak english and y try make the exercise and is a practice good xd
Brian Voong
4 years ago
Alex Grinberg
4 years ago
Brian, is there a difference if I use: DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.collectionView.reloadData() } for delay on the search instead of the timer you configured?
Brian Voong
4 years ago
Alex Grinberg
4 years ago
Thanks Brian! Love your courses... :)
Shqtucke
4 years ago
Great lesson... I have one Contextual closure type error... can you assist? func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { print(searchText) timer?.invalidate() timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { (_) in Service.shared.fetchApps(searchTerm: searchText) { (res, err) in self.appResults = res DispatchQueue.main.async { self.collectionView.reloadData() } } }) }
Shqtucke
4 years ago
It won't let me use (res, err)... if I leave out the err it works
Shqtucke
4 years ago
Never mind... I figured it out.
jdhindsa
4 years ago
Hi Brian, I was wondering if you'd be able to help me with a question. One thing I'm struggling with is how you know what the names of the properties are that are part of certain classes in UIKit. For example, you used the searchController property of the UISearchController class and just assigned the UISearchController object you created to it. I didn't know it was that simple. How did you become aware of the various properties that each UI element has as part of it's class? Is it through the documentation?
Brian Voong
4 years ago
jdhindsa
4 years ago
Okay, thank you Brian. I just don't understand why the Apple documentation is not complete in that way. I'll end up writing way more code or getting stuck on things that are trivial because of it. In your setupSearchBar function, I was also confused why some properties were set off of the searchController local variable as opposed to navigationItem.searchController. I don't understand how you know which one to choose when setting property values.
Brian Voong
4 years ago
jdhindsa
4 years ago
Thank you Brian! You're an awesome teacher. I'm going to buy all your courses!!
dneckles
4 years ago
I am in the exact same boat, my reason is that the docs are built by engineers for engineers only and that thru time and practice we will get there..
axel2018prena
4 years ago
how to do something like this with firebase
axel2018prena
4 years ago
i mean Search Bar Controller
Brian Voong
4 years ago
RichyCode
4 years ago
not ideal but i wrote a function to fix the space issue in the search term func urlifyWithPercent(string: String) -> String { let str = string.components(separatedBy: " ") let arr = str.filter( { $0 != "" }) let newString = arr.joined(separator: "%20") return newString } to use:- let urlString = "https://itunes.apple.com/search?term=\(urlifyWithPercent(string: searchTerm))&entity=software"
Brian Voong
4 years ago
RichyCode
4 years ago
cheers Brian, definitely beats writing a function to re invent the wheel.... :-)
inforsrinivasan@gmail.com
3 years ago
Hi, Just an update for anyone following this project from iOS 12.0, searchController.dimsBackgroundDuringPresentation = false // deprecated from iOS 12.0 instead use, searchController.obscuresBackgroundDuringPresentation = false Thanks.
vamshikrishna
3 years ago
When i click on search bar app is stopping/freezing donno what happening. I am using swift 5 and Xcode 11.1
frankusu
3 years ago
Hey Brain cool throttling technique! Was wondering about the technique of resigningFirstResponder() vs search throttling? // UISearchBarDelegate func searchBarSearchButtonClicked(_ searchBar: UISearchBar){ // pass text here since search button clicked? searchBar.resignFirstResponder() }
Brian Voong
3 years ago
frankusu
3 years ago
HAHA! clearly I don't know what I'm talking about. (thanks for the dismiss keyboard thing ) I think my question was, why not call Service.shared.fetchApps once when the user clicks 'Search' on the keyboard. Instead of feeding every character into 'searchText' Does it have to do with the UX and the responsive updates?
Brian Voong
3 years ago
frankusu
3 years ago
cool thanks !
Mohamed Ibrahim Fetyany
3 years ago
hey brain hope you are doing well, thank you for these work I have a problem when I run the project in iPhone 6 when collection view is empty UISearchController didn't appear and I can't search for data but when I run in iPhone x max is work fine can you help me to fix this ... thanks, again.
Brian Voong
3 years ago
Mohamed Ibrahim Fetyany
3 years ago
yes I am using iPhone 6 physical device per ios 13 and launch window in AppDelegate and sceneDelegate to work in more and fewer ios 13
Christopher J. Roura
2 years ago
Hi Brian, I am sorry to bother you with this but I found a bug that I cannot fix. When a user swipes instead of clicking one key at a time on the keyboard and makes use of the swipe text keyboard feature the collection view breaks and no longer scrolls. I have tried to google search the issue but because it seems to be a rare issue I just keep finding solutions on how to swipe dismiss the keyboard which isn't the issue.
HELP & SUPPORT