I really need help with this because i'm not sure how to troubleshoot this issue. I'm trying to make my view controller as though when i'm searching for a particular booth name and the value increments from Firebase, only the Booth names that are in my search bar updates instead of reloading the whole booth and updating it(Thus making my search bar useless).
Maybe my screenshots will give you a better idea of the issue. IF you still do not get it, feel free to comment and ask me because i know this is quite complicated. Thanks!
import UIKit
import FirebaseDatabase
var ref: DatabaseReference?
var databaseHandle: DatabaseHandle?
var postData2 = [String]()
var currentpostDataArray = [String]()
var filteredDataArray = [tableData]()
var tableDataArray = [tableData]()
class TableViewController: UITableViewController, UISearchBarDelegate {
#IBOutlet var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
setUpSearchBar()
ref = Database.database().reference() //set the firebase reference
// Retrieve the post and listen for changes
databaseHandle = ref?.child("Posts").observe(.value, with: { (snapshot) in
currentpostDataArray.removeAll()
postData2.removeAll()
tableDataArray.removeAll()
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
let value = String(describing: snap.value!)
let rating = (value as NSString).integerValue
tableDataArray.append(tableData(boothName: key, boothRating: rating))
}
let sortedTableData = tableDataArray.sorted(by: { $0.boothRating > $1.boothRating })
for data in sortedTableData {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
self.tableView.reloadData()
})
}
private func setUpSearchBar() {
searchBar.delegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return currentpostDataArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = currentpostDataArray[indexPath.row]
cell.detailTextLabel?.text = postData2[indexPath.row] + " ♥"
cell.detailTextLabel?.textColor = UIColor.red;
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
currentpostDataArray.removeAll()
postData2.removeAll()
if(searchText.isEmpty)
{
let sortedTableData = tableDataArray.sorted(by: { $0.boothRating > $1.boothRating })
for data in sortedTableData {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
else {
let allBooth = tableDataArray.filter{$0.boothName.lowercased().contains(searchText.lowercased())}
let sortedTableData = allBooth.sorted(by: { $0.boothRating > $1.boothRating })
for data in sortedTableData {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
tableView.reloadData()
}
//Enable "Cancel" button on Search Bar
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
searchBar.showsCancelButton = true
return true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
self.searchBar.endEditing(true)
searchBar.resignFirstResponder()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
currentpostDataArray.removeAll()
postData2.removeAll()
let sortedTableData = tableDataArray.sorted(by: { $0.boothRating > $1.boothRating })
for data in sortedTableData {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
self.tableView.reloadData()
self.searchBar.endEditing(true)
searchBar.showsCancelButton = false
searchBar.resignFirstResponder()
}
}
class tableData {
var boothName: String
var boothRating: Int
init(boothName: String, boothRating: Int) {
self.boothName = boothName
self.boothRating = boothRating
}
}
SCREENSHOTS: https://ibb.co/cN1XzG https://ibb.co/it3eeG https://ibb.co/bDMAmw
Related
I have set up a tableview that retrieves data from a firebase realtime database, and stores this data in an array ('posts') in this is the format:
(name: nil, contactEmail: Optional("35345345235"), contactPhoneNum: Optional("contact#gmail.com"), age: Optional("25"), gender: nil, lastSeen: nil, profileDescription: nil)
I want to implement a searchbar to filter the name value of the posts and return the posts which contain the searched name in the tableview, and am not sure how to do this.
Here is my code:
import UIKit
import Firebase
import FirebaseDatabase
import SwiftKeychainWrapper
import FirebaseAuth
class FeedVC: UITableViewController, UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
var currentUserImageUrl: String!
var posts = [postStruct]()
var selectedPost: Post!
var filteredPosts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
getUsersData()
getPosts()
searchBar.delegate = self
// Do any additional setup after loading the view.
// tableView.register(PostCell.self, forCellReuseIdentifier: "PostCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getUsersData(){
guard let userID = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("users").child(userID).observeSingleEvent(of: .value) { (snapshot) in
if let postDict = snapshot.value as? [String : AnyObject] {
self.tableView.reloadData()
}
}
}
struct postStruct {
let name : String!
let contactEmail : String!
let contactPhoneNum : String!
let age : String!
let gender : String!
let lastSeen : String!
let profileDescription : String!
}
func getPosts() {
let databaseRef = Database.database().reference()
databaseRef.child("firstName").queryOrderedByKey().observe( .childAdded, with: {
snapshot in
let name = (snapshot.value as? NSDictionary)!["name"] as? String
let contactEmail = (snapshot.value as? NSDictionary
)!["contactEmail"] as? String
let contactPhoneNum = (snapshot.value as? NSDictionary
)!["contactPhoneNum"] as? String
let age = (snapshot.value as? NSDictionary
)!["age"] as? String
let gender = (snapshot.value as? NSDictionary
)!["gender"] as? String
let lastSeen = (snapshot.value as? NSDictionary
)!["lastSeen"] as? String
let profileDescription = (snapshot.value as? NSDictionary
)!["profileDescription"] as? String
self.posts.append(postStruct(name: name,contactEmail:contactEmail, contactPhoneNum:contactPhoneNum, age:age, gender:gender, lastSeen:lastSeen, profileDescription:profileDescription))
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("posts count = ", filteredPosts.count)
return filteredPosts.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// tableView.dequeueReusableCell(withIdentifier: "PostCell")!.frame.size.height
return 230
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell else { return UITableViewCell() }
cell.nameLabel?.text = filteredPosts[indexPath.row].name
cell.contactEmailLabel?.text = filteredPosts[indexPath.row].contactEmail
cell.contactPhoneNumLabel?.text = filteredPosts[indexPath.row].contactPhoneNum
cell.ageLabel?.text = filteredPosts[indexPath.row].age
cell.genderLabel?.text = filteredPosts[indexPath.row].gender
cell.lastSeenLabel?.text = filteredPosts[indexPath.row].lastSeen
cell.profileDescriptionLabel?.text = filteredPosts[indexPath.row].profileDescription
print(filteredPosts)
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = posts.filter { $0.name?.lowercased().contains(searchText.lowercased()) == true }
}
}
Looping over the posts will provide element of type Post not String. Here's the fix:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = []
for post in posts {
if post.name?.lowercased().contains(searchText.lowercased()) == true {
filteredPosts.append(post)
}
}
}
Or simply use a higher-order method like filter inspired from #Jay's comment.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = posts.filter { $0.name?.lowercased().contains(searchText.lowercased()) == true }
}
I don't really know how to explain thats why I'm putting this title. But i do hope you can understand. As of right now, my searchBar is able to return results BUT i have to enter the entire name (For example: I have to type "EcoBooth" in order for the searchBar to return EcoBooth results.).
How can i make it as though if i just enter "Eco", it will return EcoBooth based on just a few strings i type?
P.S: Do look at the 2 images attached for more info.
My TableView Controller codes
import UIKit
import FirebaseDatabase
var ref: DatabaseReference?
var databaseHandle: DatabaseHandle?
var postData = [String]()
var postData2 = [String]()
var currentpostDataArray = [String]()
var tableDataArray = [tableData]()
var searchArray = [tableData]()
var inSearchMode = false
class TableViewController: UITableViewController, UISearchBarDelegate {
#IBOutlet var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
setUpSearchBar()
ref = Database.database().reference() //set the firebase reference
// Retrieve the post and listen for changes
databaseHandle = ref?.child("Posts2").observe(.value, with: { (snapshot) in
// Code to execute when a child is added under "Posts"
postData.removeAll()
postData2.removeAll()
tableDataArray.removeAll()
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
let value = String(describing: snap.value!)
let rating = (value as NSString).integerValue
postData.append(key)
postData2.append(value)
tableDataArray.append(tableData(boothName: key, boothRating: rating))
currentpostDataArray = postData
}
self.tableView.reloadData()
})
}
private func setUpSearchBar() {
searchBar.delegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return currentpostDataArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = currentpostDataArray[indexPath.row]
cell.detailTextLabel?.text = postData2[indexPath.row] + " ♥"
cell.detailTextLabel?.textColor = UIColor.red;
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchArray.removeAll()
searchArray = tableDataArray
currentpostDataArray.removeAll()
postData2.removeAll()
if !searchText.isEmpty {
for data in searchArray {
let item = data.boothName
if (searchText.lowercased().range(of: item) != nil) || data.boothName.lowercased() == searchText.lowercased() || searchText.lowercased().contains(data.boothName.lowercased())
{
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
}
if searchText.isEmpty {
loadDara()
}
self.tableView.reloadData()
}
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
switch selectedScope {
case 0:
currentpostDataArray.removeAll()
postData2.removeAll()
for data in tableDataArray {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
self.tableView.reloadData()
case 1:
currentpostDataArray.removeAll()
postData2.removeAll()
let sortedTableData = tableDataArray.sorted(by: { $0.boothRating > $1.boothRating })
for data in sortedTableData {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
self.tableView.reloadData()
default:
break
}
tableView.reloadData()
}
func loadDara() {
for data in tableDataArray {
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
}
class tableData {
var boothName: String
var boothRating: Int
init(boothName: String, boothRating: Int) {
self.boothName = boothName
self.boothRating = boothRating
}
}
Replace
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchArray.removeAll()
searchArray = tableDataArray
currentpostDataArray.removeAll()
postData2.removeAll()
if !searchText.isEmpty {
for data in searchArray {
let item = data.boothName
if (searchText.lowercased().range(of: item) != nil) || data.boothName.lowercased() == searchText.lowercased() || searchText.lowercased().contains(data.boothName.lowercased())
{
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
}
if searchText.isEmpty {
loadDara()
}
self.tableView.reloadData()
}
With
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchArray.removeAll()
searchArray = tableDataArray
currentpostDataArray.removeAll()
postData2.removeAll()
if !searchText.isEmpty {
for data in searchArray {
let item = data.boothName
if (item.lowercased().range(of: searchText.lowercased()) != nil)
{
currentpostDataArray.append(data.boothName)
let value = String(describing: data.boothRating)
postData2.append(value)
}
}
}
if searchText.isEmpty {
loadDara()
}
self.tableView.reloadData()
}
Use NSPredicate to search from array like this:
let searchPredicate = NSPredicate(format: "boothName CONTAINS[C] %#", searchText)
resultArr = (filteredArray as NSArray).filtered(using: searchPredicate)
You can prefer this link for more info about NSPredicate and also a swift code example : http://nshipster.com/nspredicate/
I am trying to download data and put it in struct objects and trying to load data in table view .I am downloading it in to array and append it to struct object.when I am taking return array.count in no of rows in section its working when I use return objectArray[section].funcName.count its not working values are getting late to download also
import UIKit
import Alamofire
class GalleryVC: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var galleryTable: UITableView!
var imageUrlArray:[String] = [String]()
var imageCount:[String] = [String]()
var funName1:[String] = [String]()
var gaimage1:String = ""
var gacount1:String = ""
var funname1:String = ""
struct Objects {
var imageName : [String]!
var imageCount : [String]!
var funcName:[String]!
}
var objectArray = [Objects]()
var objectArrayFilter = [Objects]()
var inSearchMode = false
override func viewDidLoad() {
super.viewDidLoad()
downloadGalleryList()
galleryTable.delegate = self
galleryTable.dataSource = self
searchBar.delegate = self
self.hideKeyboardWhenTappedAround()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
print(objectArray[section].funcName.count)
return objectArray[section].funcName.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier:"gallerycell", for: indexPath) as? GalleryListCell{
if inSearchMode{
cell.galleryImage.sd_setImage(with: URL(string: objectArrayFilter[indexPath.section].imageName[indexPath.row]), placeholderImage: UIImage(named: "1862205"))
cell.galleryphotono.text = objectArrayFilter[indexPath.section].imageCount[indexPath.row]+" photos"
cell.galleryFunction.text = objectArrayFilter[indexPath.section].funcName[indexPath.row]
return cell
}
cell.galleryImage.sd_setImage(with: URL(string: objectArray[indexPath.section].imageName[indexPath.row]), placeholderImage: UIImage(named: "1862205"))
cell.galleryphotono.text = objectArray[indexPath.section].imageCount[indexPath.row]+" photos"
cell.galleryFunction.text = objectArray[indexPath.section].funcName[indexPath.row]
return cell
}
else{
return UITableViewCell()
}
}
func downloadGalleryList(){
let bmiChapterUrl = URL(string:Gallery_List)!
Alamofire.request(bmiChapterUrl).responseJSON{ response in
let result = response.result
print(response)
print(result)
if let dict = result.value as? Dictionary<String,AnyObject>{
if let bmi = dict["result"] as? [Dictionary<String,AnyObject>]
{
for obj in bmi {
if let gaimage = obj["image"] as? String
{
print(gaimage)
self.gaimage1 = gaimage
self.imageUrlArray.append(gaimage)
}
if let gacount = obj["count"] as? String
{
self.gacount1 = gacount
print(gacount)
self.imageCount.append(gacount)
}
if let funname = obj["event"] as? String
{
print(funname)
self.funname1 = funname
self.funName1.append(funname)
}
}
}
}
print(self.imageUrlArray,self.imageCount,self.funName1
)
self.objectArray.append(Objects(imageName: self.imageUrlArray, imageCount:self.imageCount,funcName: self.funName1))
print(self.objectArray)
self.galleryTable.reloadData()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
view.endEditing(true)
galleryTable.reloadData()
} else {
inSearchMode = true
objectArrayFilter = objectArray.filter { $0.imageName.contains(where: { $0.contains(searchBar.text!) }) }
print(objectArrayFilter)
galleryTable.reloadData()
}
}
}
Requirement : i need to filter the JSON data in UITableView with UISearchBar so i placed UISearchBar (not UISearchBarController) to top of my view controller and i placed UITableView below to the UISearchBarand I also have api key which contains data in json format .
code in my view controller:
class FourthViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UITabBarControllerDelegate,UISearchDisplayDelegate{
var arrDict = NSMutableArray()
var FilteredData = NSMutableArray()
var userid:String!
#IBOutlet var SearchButton: UISearchBar!
#IBOutlet var SlideShow: ImageSlideshow!
#IBOutlet var MyTableView: UITableView!
#IBOutlet var PostButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.hidden = true
SearchButton.delegate = self
jsonParsingFromURL()
SlideShow.backgroundColor = UIColor.whiteColor()
SlideShow.slideshowInterval = 5.0
SlideShow.pageControlPosition = PageControlPosition.UnderScrollView
SlideShow.pageControl.currentPageIndicatorTintColor = UIColor.lightGrayColor()
SlideShow.pageControl.pageIndicatorTintColor = UIColor.blackColor()
SlideShow.contentScaleMode = UIViewContentMode.ScaleAspectFill
SlideShow.setImageInputs(alamofireSource)
}
func jsonParsingFromURL () {
if Reachability.isConnectedToNetwork() == true
{
Alamofire.request(.GET, "http://something.com", parameters: nil, encoding: .URL, headers: nil).response { (req, res, data, error) -> Void in
let dataString = NSString(data: data!, encoding:NSUTF8StringEncoding)
print(dataString)
self.startParsing(data!)
}
}
else{
let alert = UIAlertController(title: "No Internet Connection", message: "make sure your device is connected to the internet", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
func startParsing(data :NSData)
{
let dict: NSDictionary!=(try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)) as! NSDictionary
for i in 0 ..< (dict.valueForKey("ads") as! NSArray).count
{
arrDict.addObject((dict.valueForKey("ads") as! NSArray) .objectAtIndex(i))
}
MyTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell") as! FirstTableViewCell
let strTitle : NSString=arrDict[indexPath.row] .valueForKey("categoryname") as! NSString
let photoImage : NSString=arrDict[indexPath.row] .valueForKey("image1") as! NSString
let SecondImage : NSString=arrDict[indexPath.row] .valueForKey("image2") as! NSString
let ThirdImage : NSString=arrDict[indexPath.row] .valueForKey("image3") as! NSString
let FourthImage : NSString=arrDict[indexPath.row] .valueForKey("image4") as! NSString
let URL_API_HOST2:String = "https://www.imagestring.com/"
// let FourthData = NSData(contentsOfURL: NSURL(string: URL_API_HOST2 + (FourthImage as String))!)
cell.image1.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (photoImage as String)))
cell.image2.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (SecondImage as String)))
// cell.image2.image = UIImage(data: SecData!)
cell.image3.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (ThirdImage as String)))
cell.image4.sd_setImageWithURL(NSURL(string: URL_API_HOST2 + (FourthImage as String)))
cell.CategoryName.text = strTitle as String
return cell
}
Issue : I have already loaded one api key which is known as category..now i need fetch subcategory data using search bar..subcategory has another api....
Apple statement : UISearchController object manages the display of search results based on interactions with a search bar. description here
If you'r using UISearchBar
import UIKit
class TDSearchVC: UIViewController ,UITableViewDataSource,UITableViewDelegate , UISearchResultsUpdating , UISearchBarDelegate{
//MARK:- Outlets
//MARK:-
#IBOutlet var tblSearch: UITableView!
//MARK:- Properties
//MARK:-
var dataArray = [String]()
var filteredArray = [String]()
var shouldShowSearchResults = false
var searchController: UISearchController!
//MARK:- VDL
//MARK:-
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
loadListOfCountries() // get the data from file
configureSearchController() // Config Controller in VC
}
//MARK:- VC Methods
//MARK:-
func loadListOfCountries() {
// Specify the path to the countries list file.
let pathToFile = Bundle.main.path(forResource: "Country", ofType: "txt")
if let path = pathToFile {
// Load the file contents as a string.
do{
let countriesString = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
self.dataArray = countriesString.components(separatedBy: "\n")
}
catch{
print("try-catch error is catched!!")
}
tblSearch.reloadData()
}
}
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
self.tblSearch.tableHeaderView = searchController.searchBar
}
//MARK:- table datasource
//MARK:-
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if shouldShowSearchResults {
return filteredArray.count
}
else {
return dataArray.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
if shouldShowSearchResults {
cell.textLabel?.text = filteredArray[indexPath.row]
}
else {
cell.textLabel?.text = dataArray[indexPath.row]
}
return cell
}
//MARK:- search update delegate
//MARK:-
public func updateSearchResults(for searchController: UISearchController){
let searchString = searchController.searchBar.text
// Filter the data array and get only those countries that match the search text.
filteredArray = dataArray.filter({ (country) -> Bool in
let countryText: NSString = country as NSString
return (countryText.range(of: searchString!, options: .caseInsensitive).location) != NSNotFound
})
tblSearch.reloadData()
}
//MARK:- search bar delegate
//MARK:-
public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
shouldShowSearchResults = true
tblSearch.reloadData()
}
public func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
shouldShowSearchResults = false
tblSearch.reloadData()
}
}
If you'r using UITextField
import UIKit
class TDSearchVC: UIViewController , UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate{
#IBOutlet var textSearch: UITextField!
#IBOutlet var tblSearchResult: UITableView!
var arrData : [String] = []
var arrFilterData : [String] = []
var isSearch : Bool!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
isSearch = false
/*
* If date Data is in Json then use JSON Serialization
*/
arrData = ["Apple", "Banana", "Chikoo", "Brew", "Cherry", "Mango", "Lotus", "Peacock", "Temple", "Pine Apple","Glass", "Rose", "Church", "Computer", "Carrot"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK:- textfield
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
var searchText = textField.text! + string
if string == "" {
searchText = (searchText as String).substring(to: searchText.index(before: searchText.endIndex))
}
if searchText == "" {
isSearch = false
tblSearchResult.reloadData()
}
else{
getSearchArrayContains(searchText)
}
return true
}
// Predicate to filter data
func getSearchArrayContains(_ text : String) {
var predicate : NSPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", text)
arrFilterData = (arrData as NSArray).filtered(using: predicate) as! [String]
isSearch = true
tblSearchResult.reloadData()
}
// MARK:- TableView Delegates
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if isSearch! {
return arrFilterData.count
}
else{
return arrData.count
}
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var cell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
if isSearch! {
cell.textLabel?.text = arrFilterData[indexPath.row]
}
else{
cell.textLabel?.text = arrData[indexPath.row]
}
return cell
}
}
I have a class that handles the user looking for another user via the username. The looking part is done through SearchBar control. Backend is Firebase.
Here is the full code I have:
class AddFriendByUsernameTableViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
/**************************Global Variables************************/
var friendObject = FriendClass()
var friendsArray = [FriendClass]()
var friendsUsernames = [String]()
var isFirstLoading: Bool = true
var utiltiies = Utilities()
var searchActive : Bool = false
var usernames:[String]!
/**************************UI Components************************/
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func search(searchText: String? = nil){
/****************************Get Username by Auth Data****************************/
if(searchText != nil)
{
self.getAllUsersForSearchFilter({(result) -> Void in
if(result.domain == "")
{
let containsResult = self.usernames.contains(searchText!)
if(containsResult == true)
{
/*Query All information for found username*/
let reference = Firebase(url:"https://something.firebaseio.com/users/")
/****************************Get Username by Auth Data****************************/
reference.queryEqualToValue(searchText!).observeEventType(.Value, withBlock: { (snapshot: FDataSnapshot!) -> Void in
for userInstance in snapshot.children.allObjects as! [FDataSnapshot]{
}
})
}else{
print("No matching username to search Text")
}
}
})
}
}
func getAllUsersForSearchFilter(completion: (result: NSError) -> Void)
{
let errorFound:NSError = NSError(domain: "", code: 0, userInfo: nil)
let reference = Firebase(url:"https://something.firebaseio.com/users/")
reference.observeEventType(.Value, withBlock: { (snapshot: FDataSnapshot!) -> Void in
if(snapshot != nil )
{
for userInstance in snapshot.children.allObjects as! [FDataSnapshot]{
//username = (userInstance.value["username"] as? String)!
//self.usernames.append(userInstance.value["username"] as! String)
}
completion(result: errorFound)
}else{
completion(result: errorFound)
}
})
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if(usernames != nil)
{
return usernames.count
}
return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
//self.tempObjectHolder = self.data[indexPath.row]
//cell.textLabel!.text = self.tempObjectHolder["appUsername"] as? String
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let indexPathT = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRowAtIndexPath(indexPathT!)
/*Get username selected from the search results. */
self.friendObject.username = currentCell?.textLabel!.text
/*self.friendObject.name = self.tempObjectHolder["name"] as? String
self.friendObject.mobile = self.tempObjectHolder["mobile"] as? String
self.friendObject.telephone = self.tempObjectHolder["telephone"] as? String
self.friendObject.username = self.tempObjectHolder["appUsername"] as? String
self.friendObject.email = self.tempObjectHolder["email"] as? String
self.friendObject.workAddressString = self.tempObjectHolder["workAddress"] as! String
self.friendObject.homeAddressString = self.tempObjectHolder["homeAddress"] as! String*/
self.performSegueWithIdentifier("viewUserResultsSegue", sender: self)
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
search()
searchActive = false;
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
search(searchText)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "viewUserResultsSegue") {
// pass data to next view
//let destinationVC = segue.destinationViewController as! ViewResultUserProfileViewController
//destinationVC.friendObject = self.friendObject;
}
}
}
When I start typing in the the search bar, it executes and triggers an erro:
fatal error: unexpectedly found nil while unwrapping an Optional value
and this is happening because it took the firt character I entered and searched for it. I want it to search for full work (username) not first letters.
Thanks,
To do some action when the keyboard Enter is tapped, you can create an IBAction method in your view controller, such as:
#IBAction func enterDetected(sender: UITextField) {
print("Saw an 'Enter'")
}
Then connect the UITextField's "Primary Action Triggered" connection to the method in Interface Builder.