SearchController issue, when search the displayController shows a spacing from the Searchbar - ios

The issue is this:
In the storyboard, I must uncheck the Adjust Scroll View Insets, because if not do this, I will get a other issue(https://stackoverflow.com/questions/40974647/uisearchcontroller-issue-nslayoutattribute-do-not-work-in-real-device), and I don't know this if is affect the issue here.(I test in simulator, if check Adjust Scroll View Insets, the issue here will not appear )
My code
import UIKit
import SVProgressHUD
class ChooseStoreViewController: UIViewController,UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var ori_dataSource: [StoreListModel] = [StoreListModel]()
var dataSource = [String]()
var filterdDataSource = [String]()
var resultSearchController = UISearchController()
var choosedStore:StoreListModel? = nil
var userInfoFromChooseTerant:[String:Any]?
#IBOutlet weak var top_constraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
initData()
initUI()
}
// MARK: - view life
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.isNavigationBarHidden = true
}
func initData() {
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.placeholder = "search"
self.resultSearchController.searchBar.tintColor = UIColor.black
self.resultSearchController.searchBar.delegate = self
self.tableView.tableHeaderView = self.resultSearchController.searchBar
let nib = UINib(nibName: "TerantListCell", bundle: nil)
// Required if our subclasses are to use: dequeueReusableCellWithIdentifier:forIndexPath:
//tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.tableFooterView = UIView.init()
self.tableView.reloadData()
networkForStoreList()
}
func initUI() {
let backNavItem:UIBarButtonItem = UtilSwift.addBackButtonItem(nil, controlelr: self)
backNavItem.action = #selector(navBack)
// print(userInfoFromChooseTerant!)
tableView.separatorStyle = UITableViewCellSeparatorStyle.none
}
// 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.
let chooseRole: ChooseRoleViewController = segue.destination as! ChooseRoleViewController
chooseRole.userInfoFromChooseStore = self.userInfoFromChooseTerant
}
// MARK: - search delegate
func searchBarCancelButtonClicked() {
for item:NSLayoutConstraint in self.tableView.constraints {
self.view.setNeedsLayout()
if item.firstAttribute == NSLayoutAttribute.top {
item.constant = 0
}
}
}
// MARK: - searchbar delegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setValue("cancel", forKey:"_cancelButtonText")
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
}
// MARK: - private methods
func navBack() {
_ = self.navigationController?.popViewController(animated: true)
}
// MARK: - actions
#IBAction func unwindToChooseStoreVCFromChooseRole(segue: UIStoryboardSegue){
}
#IBAction func nextStepAction(_ sender: UIButton) {
/*if choosedStore == nil {
let lml_alert: LMLDropdownAlertView = LMLDropdownAlertView.init(frame: self.view.bounds)
lml_alert.showAlert(title: Global.hint, detail_Title: "select", cancleButtonTitle: "cacnel", confirmButtonTitle: "confirm", action: { (button) in
})
return
}*/
self.resultSearchController.isActive = false
if self.choosedStore != nil {
_ = self.userInfoFromChooseTerant?.updateValue(self.choosedStore!.userId, forKey: "store_id")
}
self.performSegue(withIdentifier: "ChooseStoreVCToChooseRoleVC", sender: self)
}
// MARK: - network
func networkForStoreList() {
let params:[String:String] = [
"createTime":"-1",
"userId" : self.userInfoFromChooseTerant!["affiliated_id"] as! String
]
// url_terantList
Mysevers.afpost(withHud: true, andAddressname: Global.url_listStore, parmas: params, requestSuccess: { (result) in
let stateCode = UtilSwift.getNetStateCode(result: result as Any, key: Global.net_key_stateCode)
if stateCode == 0 {
let storeArr:[[String : Any]] = UtilSwift.getNetAnyObject(result: result as Any, key: "list") as! [[String : Any]] // Global.net_key_bussines
//self.ori_dataSource = terantArr
for item:[String: Any] in storeArr {
let store_list_model: StoreListModel = StoreListModel.initStoreListModelWithDic(dic: item)
self.ori_dataSource.append(store_list_model)
}
for item:StoreListModel in self.ori_dataSource {
self.dataSource.append(item.name)
}
self.tableView.reloadData()
}else if stateCode == -1 {
SVProgressHUD.showError(withStatus: "err")
}
}, failBlcok: {
SVProgressHUD.showError(withStatus: "err")
})
}
// MARK: - tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.resultSearchController.isActive {
return filterdDataSource.count
}else {
return dataSource.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TerantListCell = tableView.dequeueReusableCell(withIdentifier: "TerantListCell", for: indexPath) as! TerantListCell
if self.resultSearchController.isActive {
cell.title_label.text = self.filterdDataSource[indexPath.row]
}else {
cell.title_label?.text = self.dataSource[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.choosedStore = self.ori_dataSource[indexPath.row]
}
// MARK: - regexp
func updateSearchResults(for searchController: UISearchController) {
self.filterdDataSource.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filterdDataSource = array as! [String]
self.tableView.reloadData()
}
}

Go to ".storyboard" file where "ChooseStoreViewController" exist. Then click on UITableView and change tableView constraints as follows:
Check Top Space constraint.

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

Strange issue, space of my UISearchController

The issue is like this:
There has space between searchbar and navbar:
And in the Debug in Hierarchy:
The table View
The wrapper View, we can see the space (20 pix)
And in the storyboard, I set the constraint to the tableView, attention: the navigationBar is draged by myself, the native is hide by me.
My Code
import UIKit
import SVProgressHUD
class StoreListViewController: UIViewController, UISearchBarDelegate, UITableViewDelegate,UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var navbar: UINavigationBar!
#IBOutlet weak var tableView: UITableView!
var ori_dataSource: [StoreListModel] = [StoreListModel]()
var dataSource = [String]()
var filterdDataSource = [String]()
var resultSearchController = UISearchController()
var choosedStore:StoreListModel? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
initData()
initUI()
}
// MARK: - init
func initData() {
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.placeholder = "search"
self.resultSearchController.searchBar.tintColor = UIColor.black
self.resultSearchController.searchBar.delegate = self
self.tableView.tableHeaderView = self.resultSearchController.searchBar
let nib = UINib(nibName: "TerantListCell", bundle: nil)
// Required if our subclasses are to use: dequeueReusableCellWithIdentifier:forIndexPath:
//tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.tableFooterView = UIView.init()
self.tableView.reloadData()
networkForStoreList()
}
func initUI() {
tableView.separatorStyle = UITableViewCellSeparatorStyle.none
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 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.
if segue.identifier == "StoreListGotoStoreDetailVC" {
let detail_vc:StoreDetailVC = segue.destination as! StoreDetailVC
detail_vc.store_info = self.choosedStore
}
}
// MARK: - delegate
func searchBarCancelButtonClicked() {
for item:NSLayoutConstraint in self.tableView.constraints {
if item.firstAttribute == NSLayoutAttribute.top {
item.constant = 0
}
}
}
// MARK: - searchbar delegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setValue("cancel", forKey:"_cancelButtonText")
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 0
}
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 64
}
}
}
// MARK: - private methods
// MARK: - actions
// MARK: - unwind
#IBAction func unwindToStoreListVCFromStoreDetailVC(segue: UIStoryboardSegue) {
}
// MARK: - network
func networkForStoreList() {
let userStatic: UserStaticSwift = UserStaticSwift.sharedInstance()
let params:[String:String] = [
"createTime":"-1",
"userId" : userStatic.userId
]
// url_listUsers
Mysevers.afpost(withHud: true, andAddressname: Global.url_listStore, parmas: params, requestSuccess: { (result) in
let stateCode = UtilSwift.getNetStateCode(result: result as Any, key: Global.net_key_stateCode)
if stateCode == 0 {
let userArr:[[String : Any]] = UtilSwift.getNetAnyObject(result: result as Any, key: "list") as! [[String : Any]] // Global.net_key_bussiness
//self.ori_dataSource = terantArr
for item:[String: Any] in userArr {
let store_list_model: StoreListModel = StoreListModel.initStoreListModelWithDic(dic: item)
self.ori_dataSource.append(store_list_model)
}
for item:StoreListModel in self.ori_dataSource {
self.dataSource.append(item.name)
}
self.tableView.reloadData()
}else if stateCode == -1 {
SVProgressHUD.showError(withStatus: "err")
}
}, failBlcok: {
SVProgressHUD.showError(withStatus: "fail")
})
}
// MARK: - tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.resultSearchController.isActive {
return filterdDataSource.count
}else {
return dataSource.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TerantListCell = tableView.dequeueReusableCell(withIdentifier: "TerantListCell", for: indexPath) as! TerantListCell
if self.resultSearchController.isActive {
cell.title_label.text = self.filterdDataSource[indexPath.row]
}else {
cell.title_label?.text = self.dataSource[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.choosedStore = self.ori_dataSource[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
self.performSegue(withIdentifier: "StoreListGotoStoreDetailVC", sender: self)
}
// MARK: -
func updateSearchResults(for searchController: UISearchController) {
self.filterdDataSource.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filterdDataSource = array as! [String]
self.tableView.reloadData()
}
}
ATTEMPT - 1
When I uncheck the Adjust Scroll View Insets, first come into the vc, the issue is nonexistent, but if I click the searchBar, the issue will come again, I suspect my code if is somewhere mistake:
ATTEMPT - 2
If I try this code below:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 44 // before is 64.
}
}
}
Since I don't know how you constraints your views. I guess the problem is due to automaticallyAdjustsScrollViewInsets. You should automaticallyAdjustsScrollViewInsets = false of your ViewController. Or you should constraints your UITableView to View.Top instead of TopLayoutGuide.Bottom.
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 44 // changes this one line and check it if any problem then put comment below.
}
}
}
After many attempt:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 64
}
}
// set this help me! :)
tableView.contentInset = UIEdgeInsets.zero
tableView.scrollIndicatorInsets = UIEdgeInsets.zero
}

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)
}
}

UISearchController crash when selected

I tried to implement a UISearchController into my ViewController. However, when I try to open up the Controller from a button it crashes the application and there is no error given to me from Xcode. I am using Backendless to store users and to retrieve them. I want to search through them.
Here is my code. I don't know what I am doing wrong :/ I would really appreciate the help.
import UIKit
protocol ChooseUserDelegate {
func chreatChatroom(withUser: BackendlessUser)
}
class ChooseUserViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var delegate: ChooseUserDelegate!
var users: [BackendlessUser] = []
var filteredUsers = [BackendlessUser]()
var resultSearchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
loadUsers()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableviewDataSorce
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filteredUsers.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!); let array = (self.users as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.filteredUsers = array as! [BackendlessUser]
self.tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if resultSearchController.active
{
return self.filteredUsers.count
} else {
return users.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell?
if self.resultSearchController.active
{
let userFiltered = filteredUsers[indexPath.row]
cell!.textLabel?.text = userFiltered.name
} else {
let user = users[indexPath.row]
cell!.textLabel?.text = user.name
}
return cell!
}
//MARK: UITableviewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let user = users[indexPath.row]
delegate.chreatChatroom(user)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.dismissViewControllerAnimated(true, completion: nil)
}
//MARK: IBactions
#IBAction func cancelButtonPressed(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
//MARK: Load Backendless Users
func loadUsers() {
let whereClause = "objectId != '\(backendless.userService.currentUser.objectId)'"
let dataQuery = BackendlessDataQuery()
dataQuery.whereClause = whereClause
let dataStore = backendless.persistenceService.of(BackendlessUser.ofClass())
dataStore.find(dataQuery, response: { (users : BackendlessCollection!) -> Void in
self.users = users.data as! [BackendlessUser]
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = self.resultSearchController.searchBar
self.tableView.reloadData()
}) { (fault : Fault!) -> Void in
print("Error, couldnt retrieve users: \(fault)")
}
}
}
Your resultSearchController is nil before it is used. It's set in a closure that almost certainly sets it after it's needed when setting up the view. To fix it, just move this initialization code to something earlier like viewDidLoad():
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = self.resultSearchController.searchBar

found nil while trying to segue away from a tableView

I'm getting errors whenever I try to reference the viewTable in the viewDidLoad AFTER I click on a cell to transition with the segue. Thanks a lot!!
Basically I can't use the segue unless I comment out the tableview references in view did load... but I need those in order to use the search bar and im sure it will cause problems on the way back...
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView! {
didSet {
print("tableView is set")
}
}
let searchController = UISearchController(searchResultsController: nil)
let textCellIdentifier = "TextCell"
var buildings: [(String,String)] = []
var filteredBuildings = [(String,String)]()
var goToIndex: Int?
override func viewDidLoad() {
super.viewDidLoad()
print(tableView)
var buildingTuples = loadBuildings()
for tuple in buildingTuples {
self.buildings.append(tuple)
}
self.goToIndex = -1
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView!.tableHeaderView = searchController.searchBar
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredBuildings = buildings.filter { building in
return building.0.lowercaseString.containsString(searchText.lowercaseString)
}
self.tableView.reloadData()
}
// MARK: UITextFieldDelegate Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return self.buildings.count
if searchController.active && searchController.searchBar.text != "" {
return filteredBuildings.count
}
return buildings.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
/*
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let row = indexPath.row
cell.textLabel?.text = buildings[row].0
return cell
*/
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let tuple: (String, String)
if searchController.active && searchController.searchBar.text != "" {
tuple = filteredBuildings[indexPath.row]
} else {
tuple = buildings[indexPath.row]
}
cell.textLabel?.text = tuple.0
return cell
}
// MARK: UITableViewDelegate Methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
self.goToIndex = indexPath.row
self.performSegueWithIdentifier("MainToLocation", sender: self)
//print(buildings[row].0)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MainToLocation" {
let locationViewController = (segue.destinationViewController as! LocationViewController)
locationViewController.building = self.buildings[self.goToIndex!]
}
}
extension ViewController: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
}
You can try this..
let destinationVC = self.storyboard!.instantiateViewControllerWithIdentifier("viewController") as! NextViewController
var alreadyPushed = false
if let vc = self.navigationController?.viewControllers {
for viewController in vc {
if let viewController = viewController as? NextViewController {
self.navigationController?.popToViewController(viewController, animated: true)
print("Push your controller")
alreadyPushed = true
break
}
}
}
if alreadyPushed == false {
self.navigationController?.pushViewController(destinationVC, animated: true)
}

Resources