Remove cells when searchBar text is above 0 - ios

i've created a tableView which i first did set to that it should use the filtered array if the searchController was active. However i want to first do it when the searchBar contain more than 0 characters. However this does not seem to work. Here is what i've done so far in cellForRowAtIndexPath
if (count(self.teamSearchController.searchBar.text) > 0) {
team = filteredTableData[indexPath.row] as Team
cell.textLabel?.text = team.name as String
} else {
team = self.teamArray[indexPath.row] as Team
cell.textLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 20)
cell.textLabel?.text = team.name as String
}
updateSearchResultsForSearchController
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "name CONTAINS[c] %# OR shortname CONTAINS[c] %#", searchController.searchBar.text, searchController.searchBar.text)
let array = (teamArray as NSArray).filteredArrayUsingPredicate(searchPredicate) as! [Team]
filteredTableData = array
self.tableView.reloadData()
}

You should do the checking for length of search text in updateSearchResultsForSearchController
func updateSearchResultsForSearchController(searchController: UISearchController)
{
if searchController.searchBar.text == "" {
filteredTableData = self.teamArray
} else {
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "name CONTAINS[c] %# OR shortname CONTAINS[c] %#", searchController.searchBar.text, searchController.searchBar.text)
let array = (teamArray as NSArray).filteredArrayUsingPredicate(searchPredicate) as! [Team]
filteredTableData = array
}
self.tableView.reloadData()
}
Update the code in cellForRowAtIndexPath as shown below, just have a check if the searchController is active or not
if (self.teamSearchController.active) {
team = filteredTableData[indexPath.row] as Team
} else {
team = self.teamArray[indexPath.row] as Team
cell.textLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 20)
}
cell.textLabel?.text = team.name as String

I think it is not good design to query the search bar in every table view cell. Instead, have only one array that the table view displays.
Whenever the search bar contents change, change the content of the array to be displayed in the table to the filtered array. Handle your edge case in the update method. I think the if statement you wrote should work fine.

Related

Swift 3 filterWithPredicate not working

Unable to filter array of dictionaries using predicate here is my code and i would like to filter array of dictionaries having key "category"
let searchText = searchTF.text?.replacingOccurrences(of: " ", with: "")
if (searchText?.characters.count)!>0 {
let pred = NSPredicate(format: "SELF beginswith[c] %#", searchTF.text!)
let array = NSMutableArray()
array.insert(dataArray as [AnyObject], at:NSIndexSet(indexesIn: NSMakeRange(0, dataArray.count)) as IndexSet)
dataArray.removeAllObjects()
getedArray = NSMutableArray(array: array.filtered(using: pred))
dataArray = getedArray.sortedArray(using: #selector(localizedCaseInsensitiveCompare(_ :)))
}
its giving error at last line i.e
getedArray = NSMutableArray(array: array.filtered(using: pred))
NSArray).sortedArrayUsingSelector(#selector(self.localizedCaseInsensitiveCompare))
its giving error at last line Use of unresolved identifier 'localizedCaseInsensitiveCompare'
Try this Swift native solution. filteredArray will contain the filtered and sorted array.
guard let searchText = searchTF.text, !searchText.isEmpty else { return }
let trimmedSearchText = searchText.replacingOccurrences(of: " ", with: "").lowercased()
let filteredArray = dataArray.filter( {($0["category"] as! String).lowercased().hasPrefix(trimmedSearchText) })
.sorted { ($0["category"] as! String).lowercased() < ($1["category"] as! String).lowercased() }
The code assumes that there is always a value for key category. Consider to use a custom struct or class to avoid the casts to String.
I have Achieved this by
let searchText = searchTF.text?.replacingOccurrences(of: " ", with: "")
if (searchText?.characters.count)!>0 {
// Put your key in predicate that is "category"
let searchPredicate = NSPredicate(format: "category CONTAINS[C] %#", searchText!)
let array = (dataArray as NSMutableArray).filtered(using: searchPredicate)
print ("array = \(array)")
if(array.count == 0){
searchTFActive = false;
} else {
searchTFActive = true;
}
self.aTable.reloadData()
}

Link arrays for UISearchController in Swift

I m using a UISearchController to let the user search though my data (these comes from XML and been parsed to arrays), now i want to add more then one UILabel into my Cell, but these UILabel Information comes from different arrays.
As soon as i update my Search, the 2. array does not get sorted the same way like the first does.
AP = ["FIRST1","FIRST2","FIRST3","FIRST4","FIRST5"]
APSecound = ["SEC1","SEC2","SEC3","SEC4","SEC5"]
var filteredTableDataAP = [String]()
var filteredTableDataAPSecound = [String]()
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableDataIcao.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (AP as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableDataAP = array as! [String]
//i think here i some how could set index of "filteredTableDataAP = filteredTableDataAPSecound" so they been filtered like the same shema
self.tableView.reloadData()
}
Override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCellSearch", forIndexPath: indexPath) as! CustomTableViewCellSearch
if (self.resultSearchController.active) {
cell.APLB.text = filteredTableDataAP[indexPath.row]
cell.APSecoundLB.text = filteredTableDataAPSecound[indexPath.row]
return cell
}
else {
cell.APLB.text = AP[indexPath.row]
cell.APSecoundLB.text = APSecound[indexPath.row]
return cell
}
}
On first run without searching the cell looks fine like
(FIRST1)(SEC1)
(FIRST2)(SEC2)
(FIRST3)(SEC3)
(FIRST4)(SEC4)
But once i search for "4" the cell looks like
(FIRST4)(SEC1)
is there any easy way to "keep the position of the second array like the one of the first"
The way i have used is below
you have two array :
AP = ["FIRST1","FIRST2","FIRST3","FIRST4","FIRST5"]
APSecound = ["SEC1","SEC2","SEC3","SEC4","SEC5"]
var getIndex = 0
if (self.SearchController.active) // check if SearchController isactive
{
//This will get the index of main array
getIndex = AP.indexOf(filteredsearchPost[indexPath.row])!
//According to example index should be 1 for "FIRST2"
. cell.APSecoundLB.text = APSecound[getIndex]
//set it with the retrived index and its done
//it will print "SEC2"
}else {
getIndex = indexPath.row
cell.APLB.text = AP[getIndex]
cell.APSecoundLB.text = APSecound[getIndex]
//Do the else part here
}
you just filtered the AP not filtered APSecound
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (AP as NSArray).filteredArrayUsingPredicate(searchPredicate)
let arraySecond = (APSecound as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableDataAP = array as! [String]
filteredTableDataAPSecound = arraySecond as! [String]
or you can use filteredResault: [[String: String?]] , [String: String?] is the Dictionary, filteredResault is Dictionary array. dict like ["AP": "FIRST1", "APSecound": "SEC1"]

How to search inside of Dictionary in Swift

In my UITableView I have cells with avatar image and name surname(UIImage and Label). And I want to search inside of my UITableView. So, when I type my user's name or surname it would show user's name surname with the avatar image.
Now, I can search just inside of an array with the next code:
var rosters = [String: UIImage]()
var displayNames = [String]()
var filteredTableData = [String]()
// Here I remove all elements from the array and add to it user display name and avatar
rosters.removeAll(keepCapacity: false)
for user in OneRoster.buddyList.fetchedObjects! {
var roster = OneRoster.userFromRosterForJID(jid: user.jidStr)
var image = OneChat.sharedInstance.xmppvCardAvatarModule?.photoDataForJID(roster?.jid)
rosters[user.displayName] = UIImage(data: image!)!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> onlineUserCell {
let cell:onlineUserCell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! onlineUserCell
if (self.resultSearchController.active) {
cell.username.text = filteredTableData[indexPath.row]
//cell.avatarImage.image = images[indexPath.row]
return cell
}
}
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)
displayNames.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
for (name, image) in rosters {
displayNames.append(name)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (displayNames as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
}
let array = (displayNames as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
So, this code searches just among name surname, without avatar image. I thought, that I can use dictionary, as:
var users = [UIImage: String]()
and later search by String and show as UIImage and String together in the cell. But I searched a lot and couldn't found how to search, that later I can search by String and to get result with UIImage, too.
Any ideas?
Searching the dictionary could be done by just accessing the values from the dictionary and searching them like
var users = [UIImage: String]()
let values = Array(users.values)
However this use of dictionary seems a bit wrong as you will never look up a value based on the UIImage I guess.
What you should use instead then would be a tuple or a class that holds both UIImage and String
var users = [(image:UIImage,name:String)]()
you can then simply filter the values like
users.filter { (element:(image:UIImage, name:String)) -> Bool in
return element.name.containsString(searchfrase)
}

Searching through objects in array swift

I'm trying to create a search function using the UISearchController. However i cant seem to make it work with my Team Object. I've started by creating a Team Object which contain a id, name and shortname. Then i'm retrieving the teamData from a url and adding the Team Objects into an array which is populated into a tableView. This tableView contain a searchController which is suppose to filter the Data, but nothing happens.
arrays
var teamArray = Array<Team>()
var filteredTableData = [String]()
GetTeams function
func getTeams(url: String) {
isApiCalling = true
request(.GET, url, parameters: nil)
.response { (request, response, data, error) in
if error == nil {
let data: AnyObject = data!
let jsonArray = JSON(data: data as! NSData)
for (key: String, subJson: JSON) in jsonArray {
// Create an object and parse your JSON one by one to append it to your array
var newTeamObject = Team(id: subJson["id"].intValue, name: subJson["name"].stringValue, shortname: subJson["shortname"].stringValue)
self.teamArray.append(newTeamObject)
}
self.isApiCalling = false
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
}
CellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("teamCell", forIndexPath: indexPath) as! TeamCell
cell.textLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 20)
cell.textLabel?.text = self.teamArray[indexPath.row].name as String
if (self.cellSelected.containsObject(indexPath)) {
cell.accessoryView = cell.accessoryCheck
} else {
cell.accessoryView = cell.accessoryUncheck
}
return cell
}
FilterData
func updateSearchResultsForSearchController(searchController: UISearchController)
{
filteredTableData.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
let array = (teamArray as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tableView.reloadData()
}
Team Objects
class Team{
var id: Int!
var name: NSString!
var shortname: NSString!
init(id: Int, name:NSString, shortname: NSString) {
self.id = id
self.name = name
self.shortname = shortname
}
}
The objects in the teamArray don't have a SELF property. You can't use SELF to search in all the properties of the object at once. You have to give the name of the property, and if you want to search in more than one you have to add all those properties to the predicate.
I would think it's enough for you to search in the name property like so:
let searchPredicate = NSPredicate(format: "name CONTAINS[c] %#", searchController.searchBar.text)
If you need in more properties you do like this:
let searchPredicate = NSPredicate(format: "name CONTAINS[c] %# OR shortname CONTAINS[c] %#", searchController.searchBar.text, searchController.searchBar.text)
Can you post the definition of your Team object, and any sub-objects that it contains? (TeamData).
Also indicate where you expect the search text to appear in your team object.
I haven't used NSPRedicate a lot, but my understanding of the CONTAINS comparison is that it checks an individual field to see if it contains a substring. I don't think it will check all fields of the objects you're searching. That seems like what you're expecting.
let searchPredicate = NSPredicate(format: "name contains[c] %#", searchWord)
self.filteredArray = self.array.filteredArrayUsingPredicate(searchPredicate)

TableView doesnot populate data for the first time while tapping on Search bar

I am trying to implement search bar through UISearchController and implemented the delegate as
func updateSearchResultsForSearchController(searchController: UISearchController) {
filteredTableData.removeAll(keepCapacity: true)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tblView.reloadData()
}
However the tableview doesn't get populate with data when we tap on the search bar. Otherwise it works all fine.
I also tried checking the text of search bar >1 or not, but it works at the initial but gives me error on backspace. What is the hack?
you should implement UISearchbarDelegate's this method
searchBar:textDidChange:
so your line will be
func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
filteredTableData.removeAll(keepCapacity: true)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchBar.text)
let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tblView.reloadData()
}
You need to set searchBar.delegate to self before this
The solution to my problem is as
func updateSearchResultsForSearchController(searchController: UISearchController) {
if count(searchController.searchBar.text) > 0{
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tblView.reloadData()
}else if count(searchController.searchBar.text) == 0 {
filteredTableData = tabledata
self.tblView.reloadData()
}
you can either do as Saad idea as :
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if count(searchBar.text) > 0{
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchBar.text)
let array = (tabledata as NSArray).filteredArrayUsingPredicate(searchPredicate)
filteredTableData = array as! [String]
self.tblView.reloadData()
}else if count(searchBar.text) == 0 {
filteredTableData = tabledata
self.tblView.reloadData()
}
}

Resources