Search bar not working in Swift 4 IOS App - ios

I have implemented a search bar to search for users, but nothing shows up in the table view when I search for something. I have attached a picture of my view controller below.
View Controller:
This view controller shows a list of all the users and the search bar is supposed to help the user find a username.
import UIKit
class FindFriendsViewController: UIViewController {
var users = [User]()
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var searchItem = [String]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
tableView.rowHeight = 71
let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:)))
tap.cancelsTouchesInView = false
self.view.addGestureRecognizer(tap)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UserService.usersExcludingCurrentUser { [unowned self] (users) in
self.users = users
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
extension FindFriendsViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchItem.count
} else {
return users.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FindFriendsCell") as! FindFriendsCell
// let user = users[indexPath.row]
var usernamesArr = [String]()
for user in users {
usernamesArr.append(user.username)
}
if searching {
cell.textLabel?.text = searchItem[indexPath.row]
} else {
cell.textLabel?.text = usernamesArr[indexPath.row]
cell.delegate = self
configure(cell: cell, atIndexPath: indexPath)
}
return cell
}
func configure(cell: FindFriendsCell, atIndexPath indexPath: IndexPath) {
let user = users[indexPath.row]
cell.usernameLabel.text = user.username
cell.followButton.isSelected = user.isFollowed
}
}
extension FindFriendsViewController: FindFriendsCellDelegate {
func didTapFollowButton(_ followButton: UIButton, on cell: FindFriendsCell) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
followButton.isUserInteractionEnabled = false
let followee = users[indexPath.row]
FollowService.setIsFollowing(!followee.isFollowed, fromCurrentUserTo: followee) { (success) in
defer {
followButton.isUserInteractionEnabled = true
}
guard success else { return }
followee.isFollowed = !followee.isFollowed
self.tableView.reloadRows(at: [indexPath], with: .none)
}
}
}
extension FindFriendsViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
var usernamesArr = [String]()
for user in users {
usernamesArr.append(user.username)
}
searchItem = usernamesArr.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
tableView.reloadData()
}
}

I am thinking about different problems that may occur in your code. You need to set the search bar delegate and the search Result Updater:
yourSearchController.searchBar.delegate = self
yourSearchController.searchResultsUpdater = self
If you don't have a controller, but directly the search bar:
yourSearchBar.delegate = self
yourSearchBar.searchResultsUpdater = self
And this as your delegate:
extension MasterViewController: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
extension MasterViewController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
Or maybe you are missing something like updating. Check the data's path excluding the problem one for time. First, you enter the text inside the search bar, after that check in the code where the text goes and what happens. Did you update the table view when search bar is in end editing status?
If it doesn't help you, check this wonderful tutorial which I followed times ago: Search Bar iOS

try for search username using this method to filter
searchItem = users.filter({ (objUser) -> Bool in
return (objUser.username?.lowercased() ?? "").starts(with: searchBar.text!.trim().lowercased())
})
Hope this will help you.

Related

The search bar does not search for words entered in the search field

I have a problem with the search bar, when I load the app the Json data is loaded correctly in the table view, but if I enter a word in the search field nothing happens, the data is not searched and the tableView remains the same.
ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var popularMoviesArray = [Results]()
var swiftManager = SwiftManager()
var tableViewCell = TableViewCell()
#IBOutlet weak var tableView: UITableView!
// START SEARCHBAR
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var labelError: UILabel!
var filteredMoviesArray = [Results]() {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
// END SEARCHBAR
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
swiftManager.delegate = self
// START SEARCHBAR
searchBar.delegate = self
searchBar.placeholder = "Search here..."
// END SEARCHBAR
swiftManager.fetchUrl()
}
// START SEARCHBAR
func rowOk() {
labelError.backgroundColor = UIColor.white
labelError.text = ""
}
func rowError() {
labelError.textColor = UIColor.white
labelError.backgroundColor = UIColor.red
labelError.textAlignment = .center
labelError.text = "no records found"
}
// END SEARCHBAR
// MARK: - TableView Datasource Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// START SEARCHBAR
if filteredMoviesArray.count != 0 {
rowOk()
print("OK - \(filteredMoviesArray.count)")
return filteredMoviesArray.count
} else {
rowError()
print("ERROR - \(filteredMoviesArray.count)")
return filteredMoviesArray.count
}
// END SEARCHBAR
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let item = filteredMoviesArray[indexPath.row]
cell.labelTitle.text = item.title
cell.labelYear.text = labelYearFormatter
cell.labelRate.text = String(item.vote_average ?? 0.0)
cell.labelOreview.text = item.overview
return cell
}
// MARK: - TableView Delegate Methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToDetail", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier != nil else {
return
}
let letRow = sender as? Int
switch segue.identifier {
case "goToDetail":
(segue.destination as! ViewControllerDetail).itemDetail = filteredMoviesArray[letRow!]
default:
return
}
}
}
extension SwiftManagerDelegate
//MARK: - SwiftManagerDelegate
extension ViewController: SwiftManagerDelegate {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results
self.tableView.reloadData()
}
}
func didFailWithError(error: Error) {
print(error)
}
}
extension UISearchBarDelegate
//MARK: - UISearchBarDelegate
// START SEARCHBAR
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard
let searchText = searchBar.text
else {
return
}
if searchText.isEmpty == true {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results
self.tableView.reloadData()
}
}
print("EMPTY")
return
} else {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results.filter {
$0.title!.uppercased().contains(searchText.uppercased())
}
self.tableView.reloadData()
}
}
print("FULL")
return
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
swiftManager.fetchUrl()
}
}
// END SEARCHBAR

UISearchBar to filter custom UITableViewCells

I am trying to filter custom UITableViewCells, based on one of the UILabels present in the cell.
All of the data is parsed from remote JSON, which has the model locally named Item and currently I am displaying the following in each cell successfully:
var titleLabel = UILabel()
var descriptionLabel = UILabel()
Also defined in my ItemTableViewCell class is:
func set(product: Item) {
DispatchQueue.main.async { [weak self] in
self?.titleLabel.text = item.title
self?.descriptionLabel.text = item.listPrice
}
}
These are called within my main View Controller, to which I have added a searchBar successfully and is visible within the app:
import Foundation
import UIKit
class ItemsListViewController: UIViewController {
var items = [Items]()
var itemsSearch: [Items] = []
var tableView = UITableView()
var searchController = UISearchController()
struct Cells {
static let itemCell = "ItemCell"
}
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
configureSearchController()
}
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchController.searchBar.placeholder = "Search items"
definesPresentationContext = true
var isSearchBarEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
}
func configureTableView() {
view.addSubview(tableView)
setTableViewDelegates()
tableView.rowHeight = 100
tableView.pin(to: view)
tableView.register(itemTableViewCell.self, forCellReuseIdentifier: Cells.itemCell)
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
}
extension itemsListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.itemCell) as! itemTableViewCell
let item = items[indexPath.row]
cell.set(item: item)
return cell
}
}
extension ItemsListViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
}
}
How can I filter these cells so say for instance a user searches for "Food", the only items which return would be ones which have a cell titleLabel = "food"?
I've tried to implement a function similar to the below, however it fails to achieve what I am after:
func filterContentForSearchText(_ searchText: String, category: = nil) {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.productCell) as! ProductTableViewCell
productsSearch = products.filter { (cell: cell) -> Bool in
return products.name.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()
}
Thanks in advance for any help here.
You can not filter TableViewCells. You have to filter your model data and instead of using UISearchResultsUpdating you should use UISearchBarDelegate
I have modified your code, check it.
class ItemsListViewController: UIViewController {
var items = [Items]()
var itemsSearch: [Items] = []
var filterActive = false
var tableView = UITableView()
var searchController = UISearchController()
struct Cells {
static let itemCell = "ItemCell"
}
override func viewDidLoad() {
super.viewDidLoad()
configureTableView()
configureSearchController()
}
func configureSearchController() {
searchController = UISearchController(searchResultsController: nil)
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
searchController.searchBar.placeholder = "Search items"
searchController.searchBar.delegate = self
definesPresentationContext = true
}
func configureTableView() {
view.addSubview(tableView)
setTableViewDelegates()
tableView.rowHeight = 100
tableView.pin(to: view)
tableView.register(itemTableViewCell.self, forCellReuseIdentifier: Cells.itemCell)
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
}
extension ItemsListViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filterActive ? itemsSearch.count : items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Cells.itemCell) as! itemTableViewCell
let item = filterActive ? itemsSearch[indexPath.row] : items[indexPath.row]
cell.set(item: item)
return cell
}
}
extension ItemsListViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filterItems(text: searchController.searchBar.text)
}
func filterItems(text: String?) {
guard let text = text else {
filterActive = false
self.tableView.reloadData()
return
}
self.itemsSearch = self.items.filter({ (item) -> Bool in
return item.title.lowercased().contains(text.lowercased())
})
filterActive = true
self.tableView.reloadData()
}
// Edited Version
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = nil
filterActive = false
self.tableView.reloadData()
}
}
You are doing it the wrong way.
You should not filter the cells, but instead filter the model (e.g. add and remove entries to the table view data source)
Then call reloadData - this will then access the filtered model (in cellForRowAt and create only the filtered amount of (visible) cells
To improve, use a diffable data source

SWIFT 4 UISearchBar and UITableView

I started a table view with a list of universities and created a search bar to tag along with it. The search bar works but only if I type in the name of the school exactly how it is. Is there a way I can change the it to search any part of the name and get the same results? Here's the code that I have set up.
#IBOutlet weak var schoolSearch: UISearchBar!
#IBOutlet weak var tblView: UITableView!
let schoolnames = ["Long Beach City College LAC", "California State University, Bakersfield", ...]
var searchedSchool = [String]()
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
schoolSearch.delegate = self
self.tblView.delegate = self
self.tblView.reloadData()
}
extension ChooseSchool: UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return searchedSchool.count
} else {
return schoolnames.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? TableViewCell
cell?.img.image = UIImage(named: schoolnames[indexPath.row])
cell?.lbl.text = schoolnames[indexPath.row]
_ = tableView.dequeueReusableCell(withIdentifier: "cell")
if searching {
cell?.textLabel?.text = searchedSchool[indexPath.row]
} else {
cell?.textLabel?.text = schoolnames[indexPath.row]
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "TestController") as? TestController
vc?.schoolnames = schoolnames[indexPath.row]
navigationController?.pushViewController(vc!, animated: true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchedSchool = schoolnames.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
searching = true
tblView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tblView.reloadData()
}
}
Replace
searchedSchool = schoolnames.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased()})
with
searchedSchool = schoolnames.filter { $0.range(of: searchText, options: .caseInsensitive) != nil }
I think you have to make your searchBar implement the containsString method to achieve what you need. For reference look at this link

index out of range UISearchController

I am trying to obtain the behaviour you find in whatsapp when trying to Add Participants to a group. In a tableView I have implemented UISearchController.
When a new row is selected in tableView, it is assigned an filled image(see screenshot below) and it is added/deleted to/from selectedUsers. When I start searching in the searchBar cells get rearranged and I get index out of range error, which is normal. I don't know where to go from here.
Scope:
allow the user to add/remove users whether searchBar is active or not
make sure there are no duplicate users in selectedUsers. This will be saved to DataBase.
remove cancel button that is attached on searchBar.
What have I tried?
class GroupRegistrationViewController: UITableViewController {
let searchController = UISearchController(searchResultsController: nil)
var usersArray = [User]() //users that currentUser is following
var currentUser: User!
var selectedUsers = [User]() //selected users in this controller, selected users we follow
var filteredUsers = [User]() //this property will hold the Users that the currentUser is searching for
override func viewDidLoad() {
super.viewDidLoad()
self.fetchUsers()
navigationItem.title = "GroupRegistration"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.placeholder = "Search Members"
searchController.hidesNavigationBarDuringPresentation = false
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//simply check whether the user is searching or not
if isFiltering() {
return filteredUsers.count
}
return usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GroupRegistrationTableViewCell") as! GroupRegistrationTableViewCell
if isFiltering() {
cell.user = filteredUsers[indexPath.row]
}else{
cell.user = usersArray[indexPath.row]
}
if selectedUsers.contains(cell.user) {
//User type conforms to Equatable protocol so check is allowed
cell.added = true
}
return cell
}
//this method determines if you are currently filtering results or not
func isFiltering() -> Bool {
return searchController.isActive && !searchBarIsEmpty()
}
func searchBarIsEmpty() -> Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! GroupRegistrationTableViewCell
cell.added = !cell.added
if cell.added == true {
self.addRecipient(user: cell.user)
}else{
let index = selectedUsers.index(of: cell.user)!
self.deleteRecipient(user: cell.user, index: index)
}
}
// - Helper methods
// - add
// - delete
func addRecipient(user: User) {
self.selectedUsers.append(user)
}
func deleteRecipient(user: User, index: Int) {
selectedUsers.remove(at: index)
}
}//end of class
extension GroupRegistrationViewController {
//get users from firebase
func fetchUsers() {
DatabaseReference.users(uid: currentUser.userUID).reference().child("follows").observe(.childAdded, with: { (snapshot) in
let user = User(dictionary: snapshot.value as! [String:Any])
self.usersArray.insert(user, at: 0)
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.insertRows(at: [indexPath], with: .fade)
})
}
}
//UISearchResultsUpdating Delegate
extension GroupRegistrationViewController: UISearchResultsUpdating {
func filteredContentForSearchText(searchText: String, scope: String = "All") {
filteredUsers = usersArray.filter({ (user) -> Bool in
return user.fullName.lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
/*
whenever the user adds or removes text in the search bar, the UISearchController will inform the GroupRegistrationViewController class of the change via a call to updateSearchResults(for:), which in turn calls filterContentForSearchText(_:scope:).
*/
func updateSearchResults(for searchController: UISearchController) {
filteredContentForSearchText(searchText: searchController.searchBar.text!)
searchController.searchBar.showsCancelButton = false
//CancelButton shows up when I tap for the first time in the search bar. !!!! - not desired behaviour.
//CancelButton disapears when I start typing
}
}
`class GroupRegistrationTableViewCell: UITableViewCell {`
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var displayNameLabel: UILabel!
#IBOutlet weak var checkboxImageView: UIImageView!
#IBOutlet weak var fullNameTextLabel: UILabel!
var user: User! {
didSet {
self.updateUI()
}
}
//when a row is selected added property is assigned true/false value
var added: Bool = false {
didSet{
if added == false {
checkboxImageView.image = UIImage(named: "icon-checkbox")
}else {
checkboxImageView.image = UIImage(named: "icon-checkbox-filled")
}
}
}
//add cache here
var cache = SAMCache.shared()
func updateUI() {
let profilePictureKey = "\(user.userUID)-profilePicture"
if let image = cache?.image(forKey: profilePictureKey){
self.profileImageView.image = image
self.profileImageView.layer.cornerRadius = self.profileImageView.bounds.width / 2.0
self.profileImageView.layer.masksToBounds = true
} else {
user.downloadProfilePicture { (image, error) in
self.cache?.setImage(image, forKey: profilePictureKey)
self.profileImageView.image = image
self.profileImageView.layer.cornerRadius = self.profileImageView.bounds.width / 2.0
self.profileImageView.layer.masksToBounds = true
}
}
displayNameLabel.text = user.username
checkboxImageView.image = UIImage(named: "icon-checkbox")
fullNameTextLabel.text = user.fullName
}
`}//end of class`

selecting cell in tableview while UISearchController is active, doesnt present next view?

I have made a tableview where you can select a cell, and then the viewcontroller will perform a segue to the next view, which works perfectly fine when you are not using the searchcontroller.
Then when you are using the searchcontroller, it filters the tableview as it should, and the segue is called in didSelectRowAtIndexPath, and the prepareForSegue is called. The problem then is that the view it should segue to is not presented? I can see that the code in the class connected to the view is running, so the segue is performed, it is just the view that does not follow. What am i missing
class CompanyListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
let objectMapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()
var activityIndicatorView: SWActivityIndicatorView!
var resultSearchController: UISearchController!
var allCompanies: [Company] = []
var filteredCompanies = [Company]()
override func viewDidLoad() {
super.viewDidLoad()
// set delegates
tableView.delegate = self
tableView.dataSource = self
configureSearchController()
// initialize activity indicator view
self.activityIndicatorView = SWActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.color = UIColor.lightGrayColor()
self.view.addSubview(activityIndicatorView)
self.activityIndicatorView.center = self.view.center
activityIndicatorView.startAnimating()
// fetch all records from backend
fetchAllRecords({(errors: [NSError]?) -> Void in if errors != nil {print(errors)}})
}
func configureSearchController() {
// Initialize and perform a minimum configuration to the search controller.
// Search Bar
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController?.searchBar.autocapitalizationType = .None
self.tableView.tableHeaderView = self.resultSearchController?.searchBar
resultSearchController?.dimsBackgroundDuringPresentation = false
self.resultSearchController?.searchResultsUpdater = self
definesPresentationContext = true
}
// search delegate method
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filterContentForSearchText(searchController.searchBar.text!)
}
// Filter method, which filters by companyName, and reloads tableview
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredCompanies = allCompanies.filter { company in
return company._companyName!.lowercaseString.containsString(searchText.lowercaseString)
}
tableView.reloadData()
}
// fetch all records from backend
func fetchAllRecords(completionHandler: (errors: [NSError]?) -> Void) {
let scanExpression = AWSDynamoDBScanExpression()
objectMapper.scan(Company.self, expression: scanExpression) { (response: AWSDynamoDBPaginatedOutput?, error: NSError?) in
dispatch_async(dispatch_get_main_queue(), {
// if error
if let error = error {
completionHandler(errors: [error]);
}
//if success
else {
self.allCompanies = response!.items as! [Company]
self.tableView.reloadData()
self.activityIndicatorView.stopAnimating()
}
})
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if resultSearchController.active && resultSearchController.searchBar.text != "" {
return filteredCompanies.count
}
return allCompanies.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell:CompanyListTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("companyCell") as! CompanyListTableViewCell
// set the text from the data model
let company:Company?
if resultSearchController.active && resultSearchController.searchBar.text != "" {
company = self.filteredCompanies[indexPath.row]
} else {
company = self.allCompanies[indexPath.row]
}
cell.titleLabel.text = company!._companyName
cell.imageview?.image = UIImage(named: "placeholder")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("segueToProfile", sender: self)
}
// send selected company with segue to profile
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "segueToProfile"){
let indexPath = tableView.indexPathForSelectedRow
//tableView.deselectRowAtIndexPath(indexPath!, animated: true)
let selectedRow = indexPath!.row
let profileVC = segue.destinationViewController as! ProfileViewController
if resultSearchController.active{
print(filteredCompanies[selectedRow])
profileVC.company = filteredCompanies[selectedRow]
} else {
profileVC.company = allCompanies[selectedRow]
}
}
}
}
The console is saying this, but i dont know if that has anything to do with this?
2016-11-26 15:54:07.300 Lostandfound[949:2474251] Warning: Attempt to present on which is already presenting
Here is the example of TableView with SearchBar control.You should remove didSelectRowAtIndexPath method and use prepareForSegue method for Determine the selected row in TableView.Like this...
Example:
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate
{
#IBOutlet weak var SerchBar: UISearchBar!
#IBOutlet weak var TableView: UITableView!
var searchActive : Bool = false
var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var filtered:[String] = []
override func viewDidLoad()
{
super.viewDidLoad()
}
private func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if(searchActive)
{
return filtered.count
}
return data.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.TableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
if(searchActive)
{
cell.Label.text = filtered[indexPath.row]
}
else
{
cell.Label.text = data[indexPath.row]
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any!)
{
if let cell = sender as? TableViewCell
{
let i = TableView.indexPath(for: cell)!.row
if segue.identifier == "segue1"
{
if(searchActive)
{
let name1 = segue.destination as! SecondView
name1.str = self.filtered[i]
}
else
{
let name1 = segue.destination as! SecondView
name1.str = self.data[i]
}
}
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
filtered = data.filter({ (text) -> Bool in
let tmp: NSString = text as NSString
let range = tmp.range(of: searchText, options: .caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0)
{
searchActive = false;
}
else
{
searchActive = true;
}
self.TableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
{
searchActive = true;
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar)
{
searchActive = false;
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
Your SecondView class is:
import UIKit
class SecondView: UIViewController
{
#IBOutlet weak var label: UILabel!
var str:String!
override func viewDidLoad()
{
super.viewDidLoad()
self.label.text = str
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
And your TableViewCell is:
import UIKit
class TableViewCell: UITableViewCell
{
#IBOutlet weak var Label: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
}

Resources