Swift - Search always executing before full text - ios

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.

Related

searching in the textfield of the tableview

searching in the textField of the tableView.
I need to search the names from the tableView. So for that i have tableView and textField in the UIViewController.
And i need to search from the Api. For that i have used the Alamofire method to fetch the data.
I need to search. Now i implement to display the names from the api to tableView And i got the output. But i need to implement searching .how to do in the mvvm.
my model:-
class SearchModel: NSObject {
var restaurantname :String!
init?(dictionary :JSONDictionary) {
guard let name = dictionary["name"] as? String else {
return
}
self.restaurantname = name
}
}
My viewmodel:-
class SearchViewModel: NSObject {
var datasourceModel:SearchDataSourceModel
init(withdatasource newDatasourceModel: SearchDataSourceModel) {
datasourceModel = newDatasourceModel
}
func datafordisplay(atindex indexPath: IndexPath) -> SearchModel{
return datasourceModel.dataListArray![indexPath.row]
}
func numberOfRowsInSection(section:Int) -> Int {
return (datasourceModel.dataListArray?.count)!
}
func loadData(completion :#escaping (_ isSucess:Bool) -> ()){
loadFromWebserviceData { (newDataSourceModel) in
if(newDataSourceModel != nil) {
self.datasourceModel = newDataSourceModel!
completion(true)
}
else {
completion(false)
}
}
}
//}
func loadFromWebserviceData(completion :#escaping (SearchDataSourceModel?) -> ()) {
//with using Alamofire ..............
Alamofire.request("http://www.example.com").validate(statusCode: 200..<300).validate(contentType: ["application/json"]).responseJSON{ response in
switch response.result {
case .success(let data):
print("success",data)
let result = response.result
if let wholedata = result.value as? [String:Any]{
if let data = wholedata["data"] as? Array<[String:Any]>{
// print(data["name"] as! String)
print(data)
print(response)
let newDataSource:SearchDataSourceModel = SearchDataSourceModel(array: data)
completion(newDataSource)
// }
}
}
// case .failure(let data):
// print("fail",data)
case .failure(let encodingError ):
print(encodingError)
// if response.response?.statusCode == 404 {
print(encodingError.localizedDescription)
completion(nil)
// }
}
}}
}
my DataSourcemodel:-
class SearchDataSourceModel: NSObject {
var dataListArray:Array<SearchModel>? = []
init(array :Array<[String:Any]>?) {
super.init()
var newArray:Array<[String:Any]> = []
if array == nil {
// newArray = self.getJsonDataStored44()
}
else {
newArray = array!
}
var datalist:Array<SearchModel> = []
for dict in newArray {
let model = SearchModel(dictionary: dict)
datalist.append(model!)
}
self.dataListArray = datalist
}
}
my viewController class:-
class SearchViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet private weak var tableView: UITableView!
private var searchViewModel :SearchViewModel!
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, withViewModel viewModel:SearchViewModel) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
searchViewModel = viewModel
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
// tableView.dataSource = self
// filteredData = data
searchViewModel.loadData { (isSuccess) in
if(isSuccess == true) {
self.tableView .reloadData()
}
else {
}
}
// self.tableView .reloadData()
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchViewModel.numberOfRowsInSection(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "searchcell"
var cell: SearchCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? SearchCell
if cell == nil {
tableView.register(UINib(nibName: "SearchCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? SearchCell
}
cell.setsearchData(search: searchViewModel.datafordisplay(atindex: indexPath))
// cell.name.text = searchViewModel.datafordisplay(atindex: indexPath)
// cell.name.text = filteredData[indexPath.row]
// cell.setsearchData(search: searchViewModel.datafordisplay(atindex: indexPath))
return cell
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
tableViewCell:-
class SearchCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setsearchData(search:SearchModel) {
self.name.text = search.restaurantname
}
}
This is my code .Now how to implement the searching here.
There are t way of searching.
when you enter text and press the search button.
When You type then search without using the search button.
A solution for 1:
You need to call a method on the search button
Search button.
func Search() {
predicate = NSPredicate(format: "Self.YourSearchListName beginsWith[c]%#", SearchName)
GetsearchList = YourArrayForSearch.filtered(using: predicate) as NSArray
YourTable.reloadData()
}
2nd Solution
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == self.YourTextFieldName{
Search()
}
}
for 2nd Solution don't forget to set the delegate.
filteredContactListArray is the array holding the filtered data to reload the tableview when user start searching for particular text.
#IBOutlet var searchCityTextField: UITextField!
var filteredSearchArray :SearchViewModel!
within in Viewdidload() function
searchCityTextField.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
UItextfieldDelegate Method
func textFieldDidChange(textField: UITextField) {
if textField.text == "" {
filteredSearchArray = searchViewModel// contactListArray is the actual array with all the list of data.
citiesTableView.reloadData()
}else{
filterContentForSearchText(textField.text!)
}
}
func filterContentForSearchText(searchText: String) {
filteredSearchArray = NSMutableArray(array:searchViewModel. dataListArray.filter({(ele:AnyObject) -> Bool in
return (ele as! searchViewModel).cityName.lowercased().contains(searchText.lowercased())
}))
citiesTableView.reloadData()
}
UItableviewDelegate Method
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredContactListArray.count
}

Tableview search bar not showing any data and giving some error some times when i run

I am using swift 2.0 . And i have added search bar to table view. i have run 2 times, its worked well. But now in my code its showing error :
Cannot invoke 'filter' with an argument list of type '(#noescape (Element) throws -> Bool)'
When i try to run also not able to search my table view data ,
Here is my full code:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate
{
var Table:NSArray = []
#IBOutlet weak var searchBar: UISearchBar!
var searchActive : Bool = false
var filtered:[String] = []
#IBOutlet weak var tableView: UITableView! // UITable view declaration
#IBOutlet weak var Resultcount: UILabel! // count label
let cellSpacingHeight: CGFloat = 5 // cell spacing from each cell in table view
var filteredTableData = [String]()
var resultSearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
CallWebService() // call the json method
// nib for custom cell (table view)
let nib = UINib(nibName:"customCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "cell")
searchBar.delegate = self
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
filtered = Table.filter({ (text) -> Bool in
let tmp: NSString = text as! NSString
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tableView.reloadData()
}
// every time app quit and run, switch will be in off state
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(true)
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "PremiumUser")
}
func CallWebService()
{
let UrlApi = "url"
let Url = NSURL(string: UrlApi)
let Session = NSURLSession.sharedSession()
let Work = Session.dataTaskWithURL(Url!, completionHandler: { dataTask, response, error -> Void in
if (error != nil)
{
print(error)
}
var datos:NSData = NSData(data: dataTask!)
do {
let JsonWithDatos:AnyObject! = try NSJSONSerialization.JSONObjectWithData(datos, options: NSJSONReadingOptions.MutableContainers) as! NSArray
self.Table = JsonWithDatos as! NSArray
dispatch_async(dispatch_get_main_queue()) {
if (self.Table.count>0)
{
self.Resultcount.text = "\(self.Table.count) Results"
self.tableView.reloadData()
}
}
}catch{
print("Some error occured")
}
})
Work.resume()
}
// number of sections
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
// number of rows
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}
return self.Table.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:customCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! customCell
if(searchActive){
cell.vendorName.text = filtered[indexPath.row]
} else {
cell.vendorName.text = Table[indexPath.row] as! String;
}
let item = self.Table[indexPath.row] as! [String : String]
cell.vendorName.text = item["name"]
cell.vendorAddress.text = item["address"]
return cell
}
}
i am getting error in this method func searchBar(searchBar: UISearchBar, textDidChange searchText: String) { in this line filtered = Table.filter({ (text) -> Bool in
let tmp: NSString = text as! NSString
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
Why its work one time , that time also not able to do search in my table view. Now I am suddenly getting this error.
i have implemented search controller in table view
i give you my function that filter the searched data and make an array with matching strings
func filterDestinations(searchString: String){
self.filteredDestinations.removeAll()
if(self.defaultarray.count > 0){
for obj in self.sortedDest{
if(obj.name!.rangeOfString(searchString, options: .CaseInsensitiveSearch, range: nil, locale: nil) != nil){
self.filteredDestinations.append(obj)
}
}
}
}// ends filterDestinations
after that you just reload your table view and in function cellforrowatindex you check that if search controller is active than you give data from your filltered array otherwise use your default array.
also you have to set numberofrows by check search controller is active or not.
if its active then return the filltered array count otherwise return your default array count so your app wont crash .
Just remove the closure parameter and return value type. Also rangeOfString returns nil if the string was not found. And better to cast to Swift String not NSString. You are trying to assign NSArray (basically [AnyObject] to [String]. You have to do some mapping.
filtered = table.filter {
let tmp = $0 as! String
let range = tmp.rangeOfString(searchText, options: .CaseInsensitiveSearch)
return range != nil
}.map { $0 as! String }

issue following / unfollowing users when searched for? Parse

Good Afternoon,
Today I am having some issues with parse.
I have created a UISearchController, loaded my users from parse so I can search for individual ones and I have added a following and unfollowing feature.
My Problem is when I search for a specific user and try to follow him: So I search for a specific user say "test" it shows up as it should, but when I click follow and then go back to parse to see if "I" have followed test I can a different result.
It says I have followed for example "tester" which was the first user created. Its seeming to follow the Cell and now the userId...
After that I manged to get the users in alphabetical order, but same problem here except it follows the first user in alphabetical order for example if I have a username that begins with an "A"!
I'm not sure how to fix this issue, so I'm hoping someone here does..I accept and appreciate all kind of tips and answers!
Heres my code:
class yahTableViewController: UITableViewController, UISearchResultsUpdating {
var users: [PFUser] = [PFUser]()
var followingList: [PFUser] = [PFUser]()
var searchResults: Bool = false
var resultSearchController = UISearchController()
var refresher: UIRefreshControl!
#IBOutlet var userTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.hidesNavigationBarDuringPresentation = false
self.navigationItem.titleView = resultSearchController.searchBar
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.definesPresentationContext = true
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.barStyle = UIBarStyle.Black
self.resultSearchController.searchBar.tintColor = UIColor.whiteColor()
for subview in self.resultSearchController.searchBar.subviews
{for subsubView in subview.subviews
{if let textField = subsubView as? UITextField
{textField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("Search", comment: ""), attributes: [NSForegroundColorAttributeName: UIColor.whiteColor()])
textField.textColor = UIColor.whiteColor()
}}}
tableView.tableFooterView = UIView()
self.tableView.separatorInset = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "")
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
}
//Function used to load the users on first view load or when the UI refresh is performed
private func loadUsers(searchString: String){
func refresh() {
let query = PFUser.query()
query!.whereKey("username", containsString: searchString )
self.searchResults = true
query!.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
self.users.removeAll(keepCapacity: false)
self.users += objects as! [PFUser]
self.tableView.reloadData()
} else {
// Log details of the failure
print("search query error: \(error) \(error!.userInfo)")
}
// Now get the following data for the current user
let query = PFQuery(className: "followers")
query.whereKey("follower", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if (error == nil) {
self.followingList.removeAll(keepCapacity: false)
self.followingList += objects as! [PFUser]
self.userTableView.reloadData()
} else
if error != nil {
print("Error getting following: \(error) \(error!.userInfo)")
}
})
}
self.searchResults = false
self.tableView.reloadData()
self.refresher.endRefreshing()
}}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// Force search if user pushes button
let searchString: String = searchBar.text!.lowercaseString
if (searchString != "") {
loadUsers(searchString)
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchBar.text = ""
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchString: String = searchController.searchBar.text!.lowercaseString
if (searchString != "" && !self.searchResults) {
loadUsers(searchString)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.resultSearchController.active) {
return self.users.count
} else {
return self.users.count
// return whatever your normal data source is
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let Cell = tableView.dequeueReusableCellWithIdentifier("Cell")! as UITableViewCell
if (self.resultSearchController.active && self.users.count > indexPath.row) {
let userObject = users[indexPath.row]
Cell.textLabel?.text = userObject.username
for following in followingList {
if following["following"] as? String == PFUser.currentUser()! {
//Add checkbox to cell
Cell.accessoryType = UITableViewCellAccessoryType.Checkmark
break
}}
// bind data to the search results cell
} else {
// bind data from your normal data source
}
return Cell
}
// MARK: - UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let selectedUser = users[indexPath.row] as? PFUser {
// Now get the following/following data for the current user
let query = PFQuery(className: "Followers")
query.whereKey("follower", equalTo: (PFUser.currentUser()?.objectId)!)
query.whereKey("following", equalTo: (selectedUser.objectId)!)
query.getFirstObjectInBackgroundWithBlock({ (object, error) -> Void in
if error != nil && object == nil {
// Means the record doesn't exist
self.insertFollowingRecord(selectedUser, selectedIndexPath: indexPath)
} else {
// Means record is present, so we will delete it
if let followingObject = object {
followingObject.deleteInBackground()
let cell:UITableViewCell = self.userTableView.cellForRowAtIndexPath(indexPath)!
//Remove checkbox from cell
cell.accessoryType = UITableViewCellAccessoryType.None
}
}
})
}
}
private func insertFollowingRecord (selectedUser:PFUser, selectedIndexPath: NSIndexPath) -> Void {
// Now add the data for following in parse
let following:PFObject = PFObject(className: "Followers")
following["following"] = selectedUser.objectId
following["follower"] = PFUser.currentUser()?.objectId
following.saveInBackgroundWithBlock({ (success, error) -> Void in
if success {
let cell:UITableViewCell = self.userTableView.cellForRowAtIndexPath(selectedIndexPath)!
//Add checkbox to cell
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
} else if error != nil {
print("Error getting following: \(error) \(error!.userInfo)")
}
})
}
}
You will want to implement the UISearchResultsUpdating protocol to achieve this. It uses a UISearchController (introduced in iOS 8) which has to be added programmatically instead of through the storyboard, but don't worry, it's pretty straight-forward.
This should get the job done for you
Courtesy of Russel.
class YourTableViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating {
var searchUsers: [PFUser] = [PFUser]()
var userSearchController = UISearchController()
var searchActive: Bool = false
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.userSearchController = UISearchController(searchResultsController: nil)
self.userSearchController.dimsBackgroundDuringPresentation = true
// This is used for dynamic search results updating while the user types
// Requires UISearchResultsUpdating delegate
self.userSearchController.searchResultsUpdater = self
// Configure the search controller's search bar
self.userSearchController.searchBar.placeholder = "Search for a user"
self.userSearchController.searchBar.sizeToFit()
self.userSearchController.searchBar.delegate = self
self.definesPresentationContext = true
// Set the search controller to the header of the table
self.tableView.tableHeaderView = self.userSearchController.searchBar
}
// MARK: - Parse Backend methods
func loadSearchUsers(searchString: String) {
var query = PFUser.query()
// Filter by search string
query.whereKey("username", containsString: searchString)
self.searchActive = true
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if (error == nil) {
self.searchUsers.removeAll(keepCapacity: false)
self.searchUsers += objects as! [PFUser]
self.tableView.reloadData()
} else {
// Log details of the failure
println("search query error: \(error) \(error!.userInfo!)")
}
self.searchActive = false
}
}
// MARK: - Search Bar Delegate Methods
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// Force search if user pushes button
let searchString: String = searchBar.text.lowercaseString
if (searchString != "") {
loadSearchUsers(searchString)
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
// Clear any search criteria
searchBar.text = ""
// Force reload of table data from normal data source
}
// MARK: - UISearchResultsUpdating Methods
// This function is used along with UISearchResultsUpdating for dynamic search results processing
// Called anytime the search bar text is changed
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchString: String = searchController.searchBar.text.lowercaseString
if (searchString != "" && !self.searchActive) {
loadSearchUsers(searchString)
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.userSearchController.active) {
return self.searchUsers.count
} else {
// return whatever your normal data source is
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("userCell") as! UserCell
if (self.userSearchController.active && self.searchUsers.count > indexPath.row) {
// bind data to the search results cell
} else {
// bind data from your normal data source
}
return cell
}
// MARK: - UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if (self.userSearchController.active && self.searchUsers.count > 0) {
// Segue or whatever you want
} else {
// normal data source selection
}
}
}

trying to implement the uisearchcontroller but its not giving any search result

import UIKit
class MasterTableViewController: UITableViewController, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {
//approches for uisearchbar
var searchNotes: [PFObject] = [PFObject]()
var notesSearchController = UISearchController()
var searchActive: Bool = false
// creating array for holding ojects
var noteObjects: NSMutableArray! = NSMutableArray()
var v = 0
override func viewDidLoad() {
super.viewDidLoad()
self.notesSearchController = UISearchController(searchResultsController: nil)
self.notesSearchController.dimsBackgroundDuringPresentation = true
self.notesSearchController.searchResultsUpdater = self
// Configure the search controller's search bar
self.notesSearchController.searchBar.placeholder = "Search for a user"
self.notesSearchController.searchBar.sizeToFit()
self.notesSearchController.searchBar.delegate = self
self.definesPresentationContext = true
// Set the search controller to the header of the table
self.tableView.tableHeaderView = self.notesSearchController.searchBar
print("check")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if v == 0 {
self.fetchAllObjectsFromLocalDataStore()
//self.fetchAllObjects()
}
}
// fetching data from local datastore and from parse
func fetchAllObjectsFromLocalDataStore(){
let query: PFQuery = PFQuery(className: "Sinhgad")
query.orderByDescending("createdAt")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock { ( objects, error) -> Void in
if (error == nil) {
let temp: NSArray = objects as NSArray!
self.noteObjects = temp.mutableCopy() as! NSMutableArray
self.tableView.reloadData()
}else {
print(error!.userInfo)
}
}
}
func fetchAllObjects(){
let query: PFQuery = PFQuery(className: "Sinhgad")
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
PFObject.pinAllInBackground(objects, block: nil )
self.fetchAllObjectsFromLocalDataStore()
// self.tableView.reloadData()
} else {
print(error?.userInfo)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 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 (self.notesSearchController.active) {
return self.searchNotes.count
} else {
return self.noteObjects.count
}}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MasterTableViewCell
if (self.notesSearchController.active && self.searchNotes.count > indexPath.row) {
// bind data to the search results cell
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
cell.MasterTitleLabel?.text = object["Title"] as? String
cell.MasterTextLabel.text = object["Fstory"] as? String
cell.MasterTimeLabel.text = object["Time"] as? String
cell.MasterLocationLabel.text = object["Location"] as? String
return cell
} else {
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
cell.MasterTitleLabel?.text = object["Title"] as? String
cell.MasterTextLabel.text = object["Fstory"] as? String
cell.MasterTimeLabel.text = object["Time"] as? String
cell.MasterLocationLabel.text = object["Location"] as? String
return cell
}}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (self.notesSearchController.active && self.searchNotes.count > 0) {
// Segue or whatever you want
self.performSegueWithIdentifier("openStory", sender: self)
} else {
self.performSegueWithIdentifier("openStory", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let upcoming: AddNoteTableViewController = segue.destinationViewController as! AddNoteTableViewController
if (segue.identifier == "openStory"){
let indexPath = self.tableView.indexPathForSelectedRow!
let object: PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
upcoming.object = object
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
#IBAction func btnReload(sender: AnyObject) {
fetchAllObjects()
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete ){
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
// the below for deleting the selected cell's object from server's database
// object.deleteInBackground()
//the below for deleting the selected cell's object from localstorage
object.unpinInBackground()
self.noteObjects.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
// MARK: - Parse Backend methods
func loadSearchUsers(searchString: String) {
let query: PFQuery = PFQuery(className: "Sinhgad")
query.orderByDescending("createdAt")
// Filter by search string
query.whereKey("Notes", containsString: searchString)
self.searchActive = true
query.findObjectsInBackgroundWithBlock {(objects, error) -> Void in
if (error == nil) {
self.searchNotes.removeAll(keepCapacity: false)
self.searchNotes += objects as [PFObject]!
self.tableView.reloadData()
} else {
// Log details of the failure
print("search query error: \(error) \(error!.userInfo)")
}
self.searchActive = false
}
}
// MARK: - Search Bar Delegate Methods
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// Force search if user pushes button
let searchString: String = searchBar.text!.lowercaseString
if (searchString != "") {
loadSearchUsers(searchString)
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
// Clear any search criteria
searchBar.text = ""
// Force reload of table data from normal data source
}
// MARK: - UISearchResultsUpdating Methods
// This function is used along with UISearchResultsUpdating for dynamic search results processing
// Called anytime the search bar text is changed
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchString: String = searchController.searchBar.text!.lowercaseString
if (searchString != "" && !self.searchActive) {
loadSearchUsers(searchString)
}
}
}
The above code is for retrieving stored objects from parse's server and from local storage and show them in table view.
Everything is working fine but I am trying to implement searchbar for adding searching function into my app. The problem is that when am running the app its showing the searchbar but when interacting with search bar its moving to upside and disappearing and when am typing anything.
I am not getting any search result and in NSLog am getting this :
2015-12-03 16:43:48.769 Notes[1015:56944] Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<UISearchController: 0x7ff2d48165a0>)
I know am missing something and its not the right way to achieve that function.
If somebody knows how to do it correctly or what am missing than please let me know , thanks and sorry if the way am asking question is not proper !
i just figured out that my 'searchNotes' var of Pfobject have nothing i mean its empty ! for that i tried
cell.MasterTitleLabel?.text = searchNotes["Title"] as! String
but its giving error
cannot subscript a value of type '[PFObject]' with an index of type 'string'
i know its because i declared searchNotes as
searchNotes [PFObject] = [PFObject]()
i should do it something like
searchNotes PFObject = PFObject()
but when am doing this its giving so many errors please help if somebody's know how to fix this
Maybe you shouldn't user PFObject directly.
Can you use another class instead of PFObject
private class object {
var mTitle : String!
var mStory : String!
var mTime : String!
var mLocation : String!
}
And use your code here
let obj : object = object()
obj.mTitle = PFObject["title"];
...etc

Filter an Array of data for use in a UITableView

I'm trying to filter an array that I create based on objects (as Strings) that I queried. They show up great, now I just want to filter and remake the array so that I can filter out the information I need. I'm not sure why I'm getting "Result of call 'filter' Is unused" in Xcode. I looked around but I can't figure this one out.
import UIKit
class RegionStoreTableViewController: UITableViewController, UISearchBarDelegate {
var selectedRegionStore : String? = nil
var selectedRegionStoreIndex : Int? = nil
var dataArray = [String]()
var filteredArray = [String]()
var employeeType : String? = nil
var searchText = ""
#IBOutlet weak var regionStoreSearchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
let prefs = NSUserDefaults.standardUserDefaults()
if prefs.valueForKey("EmployeeType") != nil {
employeeType = prefs.valueForKey("EmployeeType") as! String
// Employee Type
// Retail
if employeeType == "Retail" {
self.navigationItem.title = "Store Selector"
let query = PFQuery(className: "Stores")
query.orderByAscending("rStoreNumber")
query.findObjectsInBackgroundWithBlock({ (store: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
for store in store! {
let theStore = store["storeName"] as! String
let storeNumber = store["rStoreNumber"] as! String
let storeString = storeNumber + " - " + theStore
print(theStore)
self.dataArray.append(storeString)
self.tableView.reloadData()
}
}
})
}
if employeeType == "Corporate" {
let query = PFQuery(className: "Regions")
query.orderByAscending("regionName")
query.findObjectsInBackgroundWithBlock { (region: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
for region in region! {
let theRegion = region["regionName"] as! String
print(theRegion)
self.dataArray.append(theRegion)
self.tableView.reloadData()
}
} else {
print(error)
}
}
}
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(dataArray.count)
return dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("RegionStoreCell", forIndexPath: indexPath)
if searchText.isEmpty {
cell.textLabel?.text = dataArray[indexPath.row]
}
if searchText != "" {
dataArray.filter() {nil != $0.containsString(searchText) }
}
if indexPath.row == selectedRegionStoreIndex {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
return cell as UITableViewCell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let index = selectedRegionStoreIndex {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0))
cell?.accessoryType = .None
}
selectedRegionStoreIndex = indexPath.row
selectedRegionStore = dataArray[indexPath.row]
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.accessoryType = .Checkmark
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SaveSelectedRegionStore" {
let cell = sender as! UITableViewCell
let indexPath = tableView.indexPathForCell(cell)
selectedRegionStoreIndex = indexPath?.row
if let index = selectedRegionStoreIndex {
selectedRegionStore = dataArray[index]
}
}
}
// MARK: Search Bar
// delegate in story board
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchBar.showsCancelButton = true
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchBar.showsCancelButton = false
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// add minimum length of search
searchText = searchBar.text!
self.tableView.reloadData()
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
// clear out search box
searchBar.text = nil
// clear out search variable
searchText = ""
// reload the table
self.tableView.reloadData()
// hide keyboard
searchBar.resignFirstResponder()
}
}
Any suggestions?
I think you need to store your filtered array into another array.
let filterArray = dataArray.filter() {nil != $0.containsString(searchText)

Resources