Why my search bar is not working? - ios

I have tried to solve this for a couple of hours. I am a newbie in IOS and want to develop a bucket list with a search bar. The codes have no problem in compilation but when i make input in the search bar, it won't show any search result. I don't know where the problem is.
btw: I have two suspects:
1. I tried to print the status, and it seems the searchBar is never active. How to open it?
2. Does it have anything to do with var missions' data
type as Mission? It is something I am not familiar with.
Please see the following codes:
import UIKit
class BucketListViewController:UITableViewController, MissionDetailsViewControllerDelegate, MissionEditViewControllerDelegate, UISearchBarDelegate{
var searchController = UISearchController(searchResultsController: nil)
#IBOutlet weak var searchBar: UISearchBar!
var searchActive : Bool = false
var filtered:[String] = []
var missions:[String] = ["Sky diving", "Live in Hawaii"]
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
self.searchDisplayController!.searchResultsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
}
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 = missions.filter({ (text) -> Bool in
let tmp: NSString = text
let range = tmp.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
return range.location != NSNotFound
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// dequeue the cell from our storyboard
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell")!
if(searchActive){
print("search active!")
cell.textLabel?.text = filtered[indexPath.row]
} else {
cell.textLabel?.text = missions[indexPath.row]
}
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive){
return filtered.count
} else {
return missions.count
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "AddNewMission" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! MissionDetailsViewController
controller.delegate = self
}
if segue.identifier == "EditMission" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! MissionEditViewController
controller.delegate = self
}
}
func missionDetailsViewController(controller: MissionDetailsViewController, didFinishAddingMission mission: String) {
dismissViewControllerAnimated(true, completion: nil)
missions.append(mission)
tableView.reloadData()}
func missionEditViewController(controller: MissionEditViewController, didFinishEditingMission mission: String, atIndexPath indexPath: Int) {
dismissViewControllerAnimated(true, completion: nil)
missions[indexPath] = mission
tableView.reloadData()
}
}

From the project you have shared there is a problem in your cellForRowAtIndexPath method.
replace
cell.textLabel?.text = filtered[indexPath.row] as? String
with
cell.textLabel?.text = filtered[indexPath.row].details
And it will work fine.
Your complete code will be:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// dequeue the cell from our storyboard
let cell = tableView.dequeueReusableCellWithIdentifier("MissionCell")!
// if the cell has a text label, set it to the model that is corresponding to the row in array
if(searchActive){
print("search active!")
cell.textLabel?.text = filtered[indexPath.row].details
} else {
cell.textLabel?.text = missions[indexPath.row].details
}
return cell
}

Related

Add a Searchbar on TableView but no response

Referring to shrikar's work - ://shrikar.com/swift-ios-tutorial-uisearchbar-and-uisearchbardelegate/, I try to build a searchbar in table view. The tableview works fine when no adding search text. The problem is no response and error message when add search text.
I wonder something wrong. Could anybody help us? Thanks.
import UIKit
import SDWebImage
class ArticleListViewController: UITableViewController, UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
var searchActive : Bool = false
var filtered = [Article]()
var articles = [Article](){
didSet{
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
downLoadLatestArticles()
}
func downLoadLatestArticles(){
Article.downLoadItem { (articles, error) in
if let error = error {
print("fail \(error)")
return
}
if let articles = articles {
self.articles = articles
}
}
}
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) {
if(searchText == " "){
searchActive = false
}else{
filtered = articles.filter ({ (article_f) -> Bool in
let tmp: String = article_f.name
let range = tmp.range(of:searchText, options: String.CompareOptions.caseInsensitive)
return range != nil
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
}
self.tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}
return articles.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ListTableCell", for: indexPath) as! ListTableCell
var article : Article
if(searchActive){
article = filtered[indexPath.row]
}
else{
article = articles[indexPath.row]
}
cell.nameLabel?.text = article.name
cell.locationLabel?.text = article.location
cell.photoView?.sd_setImage(with: article.image_URL)
return cell
}
}

'Request for rect at invalid index path' exception on cell tap

I'm working on search bar with autofill feature. Sometimes I get this errors when tapping cell in autofill TableView:
*** Assertion failure in -[UITableViewRowData rectForRow:inSection:heightCanBeGuessed:],
/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UITableViewRowData.m:1849
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at
invalid index path ( {length = 2, path = 0 -
3})'
If I comment this line searchBar.text = cell.textLabel!.text app doesn't crash.
Here is full function code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell: UITableViewCell = tableView.cellForRow(at: indexPath)!
address = cell.textLabel!.text!
searchBar.text = cell.textLabel!.text
}
How can I fix it?
UPD: Looks like it crashes after searchBar.text = cell.textLabel!.text
I've added print(searchBar.text!) and it prints correct value to console
UPD2: App crashes only if I type something in search bar, then tap somewhere on the screen to dismiss keyboard, and then tap on one of autofill cells.
Class code:
import UIKit
import Alamofire
import SwiftyJSON
class StreetSelectViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UINavigationControllerDelegate
{
var data: [String] = ["Нет данных"]
var filtered: [String] = []
var searchActive : Bool = false
#IBOutlet weak var cityNameLabel: UILabel!
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var topSpaceConstraint: NSLayoutConstraint!
#IBOutlet var gradientBackground: GradientView!
let segueIdentifier = "ShowStreetSelectSegue"
//background gradient
override func viewDidLayoutSubviews()
{
self.gradientBackground.create()
}
override func viewDidLoad()
{
super.viewDidLoad()
//side menu panGestureRecognizer
if self.revealViewController() != nil
{
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
tableView.tableFooterView = UIView()
navigationController?.delegate = self
//search bar settings
let barImage = UIImage()
searchBar.setBackgroundImage(barImage, for: .any, barMetrics: .default)
searchBar.scopeBarBackgroundImage = barImage
searchBar.tintColor = UIColor.lightGray
searchBar.setValue("Отмена", forKey:"_cancelButtonText")
searchBar.showsCancelButton = false
topSpaceConstraint.constant = self.navigationController!.navigationBar.frame.height + 8
//network
let queue = DispatchQueue(label: "com.admin.response-queue", qos: .utility, attributes: [.concurrent])
URLCache.shared.removeAllCachedResponses()
Alamofire.request("").validate()
.responseJSON(
queue: queue,
completionHandler: { response in
if let JSON = response.result.value
{
self.data.removeAll()
let json = SwiftyJSON.JSON(JSON)
print("JSON: \(json)")
for (_, object) in json
{
self.data.append(object.stringValue)
print(self.data)
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
)
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
override func viewWillAppear(_ animated: Bool)
{
cityNameLabel.text = cityName
}
//MARK: - search bar settings
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
{
searchActive = true;
self.navigationController?.isNavigationBarHidden = true
topSpaceConstraint.constant = 8
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar)
{
searchActive = false;
self.navigationController?.isNavigationBarHidden = false
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
filtered = data
tableView.isHidden = false
tableView.reloadData()
topSpaceConstraint.constant = 8
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
if !searchActive
{
searchActive = true
tableView.reloadData()
}
self.searchBar.resignFirstResponder()
address = searchBar.text!
performSegue(withIdentifier: "ShowSearchResultsSeque", sender: Any?.self)
}
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: NSString.CompareOptions.caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0)
{
searchActive = false;
}
else
{
searchActive = true;
}
if searchText.characters.count != 0
{
tableView.isHidden = true
}
else
{
tableView.isHidden = false
}
tableView.reloadData()
topSpaceConstraint.constant = 8
}
//MARK: - tableview settings
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if searchActive
{
if filtered.count == 0
{
return data.count
}
else
{
return filtered.count
}
}
else
{
return data.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if searchActive
{
if filtered.count == 0
{
cell.textLabel?.text = data.sorted()[indexPath.row]
}
else
{
cell.textLabel?.text = filtered.sorted()[indexPath.row]
}
}
else
{
cell.textLabel?.text = data.sorted()[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell: UITableViewCell = self.tableView.cellForRow(at: indexPath)!
address = cell.textLabel!.text!
self.searchBar.text = cell.textLabel!.text
print(searchBar.text!)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
cell.backgroundColor = UIColor.clear
//text color
cell.textLabel!.textColor = UIColor.white;
//cell selection color
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
cell.selectedBackgroundView = bgColorView
tableView.backgroundColor = UIColor.clear
}
}
Why you are using self.tableView.cellForRow in didSelectRowAt method, you can use your filtered datasource in didSelectRowAt method, which you have already used in cellForRowAt method. you can do following to achieve your functionality.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if searchActive
{
if filtered.count == 0
{
address = data.sorted()[indexPath.row]
}
else
{
address = filtered.sorted()[indexPath.row]
}
self.searchBar.text = address
}
}
I'm not sure why but the problem was in SearchDisplayController. After deleting it in storyboard everything works fine

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

prepareForSegue sending the wrong (delayed) string extracted from array to second view controller

In VC1, I am trying to extract a string from an array, and send it to VC2. I do this in my prepareForSegue method. However, when I run it, there is a lag:
I tap row1(apples) in VC1 it goes to VC2 and shows apples in VC2
Tap back to VC 1
Tap row2(bananas), string passes as apples to
VC2
Tap back to VC1
I tap row3(oranges) in VC1 it goes to VC2
and shows bananas in VC2
etc etc.
Below is the code I am using. If anyone could help show me where I am going wrong, it would be much appreciated. Thank you..
class HomeSearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate {
var filteredArray = [String]()
var shouldShowSearchResults = false
var searchController: UISearchController!
var databaseRef = FIRDatabase.database().reference()
var loggedInUser = AnyObject?()
var loggedInUserData = AnyObject?()
var productSearchArray = [AnyObject?]()
var productBrandArray = [String]()
var itemNameArray = [String]()
var picUrlArray = [String]()
var skuArray = [String]()
var nextScreenRow = Int()
var nextSceenRowNonSearch = Int()
var toPass = String()
var toPassSearch = String()
var initialSearchList = ["Apple", "Samsung", "Windows", "Google"]
#IBOutlet weak var tblSearchResults: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
loadListOfCountries()
configureSearchController()
tblSearchResults.delegate = self
tblSearchResults.dataSource = self
}
// MARK: Table Cells Stuff
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if shouldShowSearchResults {
return filteredArray.count
}
else {
return initialSearchList.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("homeSearchCell", forIndexPath: indexPath) as! HomeSearchTableViewCell
//note to self: need to pass on more than one variable for search
if shouldShowSearchResults {
cell.configure(filteredArray[indexPath.row], itemNameLabel: "text'", skuLabel: "TEXT")
//cell.textLabel?.text = filteredArray[indexPath.row]
}
else if shouldShowSearchResults == false{
cell.configureNISearch(initialSearchList[indexPath.row])
}
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
//to find out row and pass variable.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
//println("You selected cell #\(indexPath.row)!")spDetailSegue
if shouldShowSearchResults {
nextScreenRow = indexPath.row
// get to the next screen
self.performSegueWithIdentifier("spDetailSegue", sender: self)
}
else if shouldShowSearchResults == false{
nextSceenRowNonSearch = indexPath.row
// get to the next screen
self.performSegueWithIdentifier("searchSegue", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "spDetailSegue") {
//Checking identifier is crucial as there might be multiple
// segues attached to same view
let detailVC = segue.destinationViewController as? pDetailViewController;
detailVC!.toPassSku = skuArray[nextScreenRow]
// print("vSku", )
}
if (segue.identifier == "searchSegue"){
//print("selected indexpath = ", selectedIndex)
let detailVC = segue.destinationViewController as? SearchDetailViewController;
detailVC!.toPassSearch = initialSearchList[nextSceenRowNonSearch]
}
}
//Search Bar stuff
func configureSearchController() {
// Initialize and perform a minimum configuration to the search controller.
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.delegate = self
searchController.searchBar.sizeToFit()
//searchController.searchBar.scopeButtonTitles = ["Products", "Users"]
searchController.searchBar.barTintColor = UIColor.whiteColor()
searchController.searchBar.tintColor = UIColor.redColor()
// Place the search bar view to the tableview headerview.
tblSearchResults.tableHeaderView = searchController.searchBar
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
shouldShowSearchResults = true
tblSearchResults.reloadData()
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
shouldShowSearchResults = false
tblSearchResults.reloadData()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
if !shouldShowSearchResults {
shouldShowSearchResults = true
tblSearchResults.reloadData()
}
searchController.searchBar.resignFirstResponder()
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchString = searchController.searchBar.text
// Filter the data array and get only those countries that match the search text.
filteredArray = itemNameArray.filter({ (item_name) -> Bool in
let countryText: NSString = item_name
return (countryText.rangeOfString(searchString!, options: NSStringCompareOptions.CaseInsensitiveSearch).location) != NSNotFound
})
// Reload the tableview.
tblSearchResults.reloadData()
}
}
once try by removing below line
tableView.deselectRowAtIndexPath(indexPath, animated: true)
from your didSelectRowAtIndexPath.
as #Lu_ suggested,
are you sure that didSelectRowAtIndexPath is called before prepareForSegue? you did not put your segue action from cell to controller?
This solved the issue. Thanks!

Swift tableView.reloadData() is not working

Solution : https://stackoverflow.com/a/39638032/1106035
I am new to Swift, I need to reload my records when I click on the UIButton action. For me reload method is stop working. I tried in all the possible ways as following:
Here is the function that I call when I tap the button
#IBAction func refresh(sender: AnyObject) {
// I tried this one but doesn't works
dispatch_async(dispatch_get_main_queue()) {
self.tblNotes.reloadData()
}
// This one too doesn't works for me
self.tblNotes.reloadData()
//Neither this
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tblNotes.reloadData()
})
}
Below one is my entire Class
class ListaTrmTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate , UISearchDisplayDelegate, EditNoteViewControllerDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet var tblNotes: UITableView!
var arrNotes: Array<CKRecord> = []
var editedNoteRecord: CKRecord!
var selectedNoteIndex: Int!
var searchActive : Bool = false
var filtered:Array<CKRecord> = []
var notesArray = [ListaTrmTableViewController]()
override func viewDidLoad() {
super.viewDidLoad()
tblNotes.delegate = self
tblNotes.dataSource = self
searchBar.delegate = self
fetchNotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
if(searchActive) {
return filtered.count
}
return arrNotes.count
}
//Cell height size
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedNoteIndex = indexPath.row
performSegueWithIdentifier("viewControllerSg", sender: self)
}
//Segue to other ViewController
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewControllerSg" {
let editNoteViewController = segue.destinationViewController as! ViewController
if let index = selectedNoteIndex {
editNoteViewController.editedNoteRecord = arrNotes[index]
}
if(searchActive){
editNoteViewController.editedNoteRecord = filtered[selectedNoteIndex]
}
}
}
// Retrive data from CloudKit
func fetchNotes() {
let container = CKContainer.defaultContainer()
let privateDatabase = container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "Notes", predicate: predicate)
query.sortDescriptors = [NSSortDescriptor(key: "Title", ascending: true)]
privateDatabase.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in
if error != nil {
println(error)
}
else {
println(results)
for result in results {
self.arrNotes.append(result as! CKRecord)
}
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
self.tblNotes.reloadData()
self.tblNotes.hidden = false
})
}
}
}
func didSaveNote(noteRecord: CKRecord, wasEditingNote: Bool) {
if !wasEditingNote {
arrNotes.append(noteRecord)
}
else {
arrNotes.insert(noteRecord, atIndex: selectedNoteIndex)
arrNotes.removeAtIndex(selectedNoteIndex + 1)
selectedNoteIndex = nil
}
if tblNotes.hidden {
tblNotes.hidden = false
}
tblNotes.reloadData()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("idCellNote", forIndexPath: indexPath) as! UITableViewCell
if(searchActive){
let noteRecord: CKRecord = filtered[indexPath.row]
cell.textLabel?.text = noteRecord.valueForKey("Atitulo") as? String
} else {
let noteRecord: CKRecord = arrNotes[indexPath.row]
cell.textLabel?.text = noteRecord.valueForKey("Atitulo") as? String
}
return cell
}
// Search functions
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 = arrNotes.filter ({ (note) -> Bool in
let titles = note.objectForKey("Atitulo") as? String
//proceed as per normal
let range = titles!.rangeOfString(searchText, options: NSStringCompareOptions.CaseInsensitiveSearch)
// I returned false to isolated the problem
if let range = range { return true} else { return false}
})
if(filtered.count == 0){
searchActive = false;
} else {
searchActive = true;
}
self.tblNotes.reloadData()
}
// The big problem is here
#IBAction func refresh(sender: AnyObject) {
// I tried this one but don't works
dispatch_async(dispatch_get_main_queue()) {
self.tblNotes.reloadData()
}
// This one don't works too
self.tblNotes.reloadData()
//Neither this
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tblNotes.reloadData()
})
}
First, you need to make sure that you have set the delegate and datasource from Storyboard where your TableView exists.
Second, I think you are trying to reload data that if you don't get successfully from cloudkit because of network problem. So,tableView.reloadData() wont bring you anything until you fetch data from cloud. So, try to insert fetchNotes() inside main thread so your view will refresh.
#IBAction func refresh(sender: AnyObject) {
dispatch_async(dispatch_get_main_queue()) {
self.fetchNotes()
}
}
You need to make sure the View Controller is the delegate and data source for the UITable. This can be done through the Storyboard.

Resources