how to auto-paste text in swift? - ios

I have searchbar in my table view I want to auto search or auto-paste text in search bar when we have copied text
can I do it?
it is source code
import UIKit
class TableViewController: UITableViewController, UISearchBarDelegate {
var listEnWord = [EnWordModel]()
var filteredWord = [EnWordModel]()
var inSearchMode = false
var dbHelper = DatabaseHelper()
override func viewDidLoad() {
super.viewDidLoad()
searchaWord()
loadAllWords()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
func loadAllWords(){
listEnWord = dbHelper.getAllEnWord()
tableView.dataSource = self
tableView.delegate = self
}
func searchaWord(){
let searchBar = UISearchBar()
self.view.addSubview (searchBar)
searchBar.delegate = self
searchBar.returnKeyType = UIReturnKeyType.done
navigationItem.titleView = searchBar
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.view.endEditing(true)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if inSearchMode {
return filteredWord.count
}
return listEnWord.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! ItemMenuCell
if inSearchMode {
cell.enword = filteredWord[indexPath.row]
} else {
cell.enword = listEnWord[indexPath.row]
}
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text == nil || searchBar.text == "" {
inSearchMode = false
tableView.reloadData()
self.view.endEditing(true)
} else {
inSearchMode = true
let lower = searchBar.text!.lowercased()
filteredWord = listEnWord.filter({$0.Word?.range(of: lower, options: .anchored ) != nil})
tableView.reloadData()
tableView.setContentOffset(CGPoint.zero, animated: true)
self.view.endEditing(true)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if inSearchMode {
Singleton.ShareInstance.enwordSelected = filteredWord[indexPath.row]
} else {
Singleton.ShareInstance.enwordSelected = listEnWord[indexPath.row]
}
let des = storyboard?.instantiateViewController(withIdentifier: "DetailController")
navigationController?.pushViewController(des!, animated: true )
}
}
thanks for helping me

Sure, seems like you are looking for a way to auto search text in your clipboard. So first register clipboard text change listener in this way. Note that it only works within your application:
NotificationCenter.default.addObserver(self, selector: #selector(clipboardChanged),
name: NSNotification.Name.UIPasteboardChanged , object: nil)
Then handle the it by this function
func clipboardChanged(){
let pasteboardString: String? = UIPasteboard.general.string
if let theString = pasteboardString {
print("String is \(theString)")
// Put the string into your search bar and do the search
}
}

Related

Swift search bar(controller) memory leaks

I have main screen, with a button on which I segue to searchVC screen.I have a navigation controller between them, in searchVC there are searchController and searchBar.
Problem:I need to activate search when screen appears, but searchBar activation(tap or becomeFirstResponder() ) causes memory leaks(image below)
I tried to remove delegates and the problem disappears, but I need to know when cancel button pressed to segue/dismiss to mainVC
Code:tableView for results, resultView with label for empty results
class SearchViewController: UIViewController,UISearchBarDelegate,UISearchControllerDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var resultView: ResultView!
let searchController = UISearchController(searchResultsController: nil)
var filteredSongs = [SongListModel]()
var songs = SongListModel.fetchSongs()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search songs"
if #available(iOS 11.0, *) {
navigationItem.titleView = searchController.searchBar
navigationItem.hidesSearchBarWhenScrolling = false
// navigationController?.navigationBar.topItem?.searchController = searchController
// navigationItem.titleView?.isHidden = true
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
} else {
tableView.tableHeaderView = searchController.searchBar
}
searchController.searchBar.showsCancelButton = true
searchController.definesPresentationContext = true
searchController.searchBar.sizeToFit()
searchController.delegate = self
searchController.searchBar.delegate = self
tableView.keyboardDismissMode = .interactive
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
delay(0.1) { [unowned self] in
self.searchController.searchBar.becomeFirstResponder()
}
}
func delay(_ delay: Double, closure: #escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
searchController.searchBar.resignFirstResponder()
}
func searchBarIsEmpty() -> Bool {
// Returns true if the text is empty or nil
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredSongs = songs.filter({( song : SongListModel) -> Bool in
return song.musicFileName.lowercased().contains(searchText.lowercased())
})
tableView.reloadData()
}
func isFiltering() -> Bool {
return searchController.isActive && !searchBarIsEmpty()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchController.searchBar.endEditing(true)
searchController.searchBar.resignFirstResponder()
// searchController.searchBar.delegate = nil
// searchController.searchResultsUpdater = nil
dismiss(animated: true, completion: nil)
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PlayTilesSegue", let destinationVC = segue.destination as? TilesViewController, let selectedIndex = tableView.indexPathForSelectedRow?.row {
let song: SongListModel
if isFiltering() {
song = filteredSongs[selectedIndex]
} else {
song = songs[selectedIndex]
}
destinationVC.songFileName = song.musicFileName
navigationController?.setNavigationBarHidden(true, animated: false)
}
}
}
extension SearchViewController: UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
resultView.setIsFilteringToShow(filteredItemCount: filteredSongs.count, of: songs.count)
return filteredSongs.count
}
resultView.setNotFiltering()
return songs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "filteredCell", for: indexPath) as! FilteredSongCell
let song: SongListModel
if isFiltering() {
song = filteredSongs[indexPath.row]
} else {
song = songs[indexPath.row]
}
cell.listenSongButton.setBackgroundImage(UIImage(named: "playback"), for: .normal)
cell.filteredAuthorNameLabel.text = song.authorName
cell.filteredSongNameLabel.text = song.songName
cell.playGameButton.setTitle(song.playButton.rawValue, for: .normal)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "PlayTilesSegue", sender: indexPath)
tableView.deselectRow(at: indexPath, animated: true)
}
}
extension SearchViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
}
Image memory leaks
Deactivating the search controller on removing VC from parent helps to avoid memory leak:
override func didMove(toParent parent: UIViewController?) {
super.didMove(toParent: parent)
if parent == nil, searchController.isActive {
searchController.isActive = false
}
}
You need to set the UISearchController searchBar's delegate. Once you have done this, the addition of the delegate method searchBarCancelButtonClicked: will properly be called.
Here it is.

search bar in ios swift

I want to use search bar in my app.I am trying to use it but exceptions are coming . I have got an array of dictionary called member [[String:Anyobject]] and from this i have taken out the name and stored into an array data of type string and it is not working.
Here is my code :
import UIKit
class hcbaViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UISearchBarDelegate {
#IBOutlet var searchbar: UISearchBar!
#IBOutlet var tableview: UITableView!
var member = [[String:AnyObject]]()
var members = [String:AnyObject]()
var searchActive = true
var filtered:[String] = []
var data: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
print(data)
print("________-----------________----------")
print(member)
// Do any additional setup after loading the view.
}
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 = 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
}
self.tableview.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "MemberDirectory"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return member.count
if(searchActive){
return filtered.count
}
else{
return data.count
}
// return member.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
var display = member[indexPath.row]
cell.textLabel?.text = display["Name"] as! String?
cell.detailTextLabel?.text = display["email"] as? String
let n = display["Name"] as! String
data.append(n)
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! hcbadetailViewController
vc.kk = members
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
members = member[indexPath.row]
self.performSegue(withIdentifier: "bye", sender: nil)
}
You can try this...
class SearchNew: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, GADInterstitialDelegate{
var SearchBarValue:String!
var searchActive : Bool = false
var data : NSMutableArray!
var filtered:NSMutableArray!
#IBOutlet var searchBar: UISearchBar!
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.searchBar.showsCancelButton = false
tableView.tableFooterView = UIView(frame: CGRectZero)
/* Setup delegates */
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
self.searchBar.delegate = self
data = []
filtered = []
self.getData()
} //-----viewDidLoad closed------
func getData()
{
//insert member data within data array
data.addObject(member)
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchActive = true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchActive = false
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
searchBar.text = nil
searchBar.resignFirstResponder()
tableView.resignFirstResponder()
self.searchBar.showsCancelButton = false
tableView.reloadData()
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchActive = false
}
func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool {
return true
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
self.searchActive = true;
self.searchBar.showsCancelButton = true
filtered.removeAllObjects()
dispatch_to_background_queue
{
for xdata in self.data
{
let nameRange: NSRange = xdata.rangeOfString(searchText, options: [NSStringCompareOptions.CaseInsensitiveSearch ,NSStringCompareOptions.AnchoredSearch ])
if nameRange.location != NSNotFound{
self.filtered.addObject(xdata)
}
}//end of for
self.dispatch_to_main_queue {
/* some code to be executed on the main queue */
self.tableView.reloadData()
} //end of dispatch
}
}
func dispatch_to_main_queue(block: dispatch_block_t?) {
dispatch_async(dispatch_get_main_queue(), block!)
}
func dispatch_to_background_queue(block: dispatch_block_t?) {
let q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(q, block!)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive) {
return filtered.count
}else{
return data.count
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showDetailView") {
if let destination=segue.destinationViewController as? DetailViewController{
let path=tableView.indexPathForSelectedRow
let cell=tableView.cellForRowAtIndexPath(path!)
destination.passedValue=(cell?.textLabel?.text)
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
searchBar.resignFirstResponder()
searchBar.endEditing(true)
self.view.endEditing(true)
self.searchBar.showsCancelButton = false
self.searchBar.text=""
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")! as UITableViewCell;
if(searchActive){
cell.textLabel?.text = filtered[indexPath.row] as! NSString as String
} else {
cell.textLabel?.text = data[indexPath.row]as! NSString as String
}
return cell;
}
}
Hope it helps you.
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate {
#IBOutlet var tblview: UITableView!
#IBOutlet var searchview: UISearchBar!
var data:[String] = ["Dev","Hiren","Bhagyashree","Himanshu","Manisha","Trupti","Prashant","Kishor","Jignesh","Rushi"]
var filterdata:[String]!
override func viewDidLoad() {
super.viewDidLoad()
tblview.dataSource = self
searchview.delegate = self
filterdata = data
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filterdata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tblview.dequeueReusableCell(withIdentifier: "cell", for: indexPath)as!TableViewCell1
if filterdata.count != 0
{
cell.textview.text = filterdata[indexPath.row]
}
else{
cell.textview.text = data[indexPath.row]
}
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// filterdata = searchText.isEmpty ? data : data.filter {(item : String) -> Bool in
filterdata = searchText.isEmpty ? data : data.filter { $0.contains(searchText) }
//return item.range(of: searchText, options: .caseInsensitive, range: nil, locale: nil) != nil
tblview.reloadData()
}
let searchController = UISearchController(searchResultsController: nil)
navigationItem.hidesSearchBarWhenScrolling = true
navigationItem.searchController = searchController
Replace this method with your TableView's method
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(searchActive){
return filtered.count
}
else{
return data.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath)
var display = searchActive == true ? filtered[indexPath.row] :
data[indexPath.row]
cell.textLabel?.text = display["Name"] as! String?
cell.detailTextLabel?.text = display["email"] as? String
let n = display["Name"] as! String
data.append(n)
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)
}
}

tableview filtered rows get reloaded after selecting row

I have implemented a search bar for my tableview by:
let searchController = UISearchController(searchResultsController: nil)
and in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
tblSearchTable.delegate = self
tblSearchTable.dataSource = self
loadListOfCountries()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tblSearchTable.tableHeaderView = searchController.searchBar
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
}
My problem is that, when I search for items, the table shows the filtered rows but when I tap/click a row, the tableview rows get reloaded (all items). This is my didselectrow function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected row")
self.dismiss(animated: false, completion: nil)
}
The text selected row gets printed but the the viewcontroller isnt getting dismissed but instead, just like I said, reloads all the original items in tableview.
Here are the extensions, might need them when helping me:
#available(iOS 10.0, *)
extension Search: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchText: searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
#available(iOS 10.0, *)
extension Search: UISearchResultsUpdating {
public func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
}
And here's the search function:
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredArray.removeAll()
var x = 0
for a in dataArray{
if( a.lowercased().contains(searchText.lowercased())){
filteredArray.append(a)
}
x = x + 1
}
self.tblSearchTable.reloadData()
}
Here's the complete code:
import UIKit
import CoreData
#available(iOS 10.0, *)
class Search : UIViewController, UITableViewDelegate, UITableViewDataSource{
var dataArray = [String]()
var dataLine = [String]()
var dataColor = [String]()
var filteredArray = [String]()
var filteredLine = [String]()
var filteredColor = [String]()
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet var tblSearchTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tblSearchTable.delegate = self
tblSearchTable.dataSource = self
loadListOfCountries()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tblSearchTable.tableHeaderView = searchController.searchBar
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: UITableView Delegate and Datasource functions
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("selected row")
self.dismiss(animated: false, completion: nil)
//var ClassViewController = self.storyboard!.instantiateViewController(withIdentifier: "ViewController") as! ViewController
//ClassViewController.funcforsearch()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.isActive && searchController.searchBar.text != "" {
return filteredArray.count
}
return dataArray.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "idCell", for: indexPath as IndexPath)
if searchController.isActive && searchController.searchBar.text != "" {
cell.textLabel?.text = filteredArray[indexPath.row]
} else {
cell.textLabel?.text = dataArray[indexPath.row]
}
//cell.textLabel?.text = candy.name
//cell.detailTextLabel?.text = candy.category
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
// MARK: Custom functions
func loadListOfCountries() {
//get some array here
self.tblSearchTable.reloadData()
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredArray.removeAll()
var x = 0
for a in dataArray{
if( a.lowercased().contains(searchText.lowercased())){
filteredArray.append(a)
}
x = x + 1
}
self.tblSearchTable.reloadData()
}
}
#available(iOS 10.0, *)
extension Search: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchText: searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
#available(iOS 10.0, *)
extension Search: UISearchResultsUpdating {
public func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
}
Thanks!

Resources