didSelectRowAtIndexpath not responding to clicks - swift

I'm making a revision app for high school students. In this view, the user should be able to select the units that they want to study for a certain subject, and the index path of the selected units will be stored in an int array and passed on to the next view for displaying images. Unfortunately, the didSelectRowAt method is not responding for some reason.
The delegate and data source are set correctly, I know that it is not getting called as I wrote a print statement in the function, and nothing was printed in the console when I click on any one the table cells.
var units = [String]()
var selectedRows = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return units.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "unitCell", for: indexPath) as! UnitCell
cell.textLabel?.text = units[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedRows.append(indexPath.row)
print(selectedRows)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! ImageView
destination.folderNames = selectedRows
}
I expect an int array of row indexes of selected cells. But right now it is just empty.

If the code your showing in your question is accurate, the signature of the didSelectRowAt method is incorrect. It should be:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Note the leading "_" for the first parameter. If your class is a UITableViewController, you'll also need to add an override keyword.
If your code is already using this signature, please update your question to reflect that.
Also, this leading code cannot be correct. Please update it to what you're actually using,
var units = String var selectedRows = Int

You should use delegate method
optional func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath)
Instead of your existing one
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath)
Try and share your results.

First thing is that your didSectRow is depricated so please use
below one
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Secondly You have to set your TableView Delegate to Self like below
tableView.delegate = self

Related

Swift - How to access cells name

import UIKit
class TableViewControllerOne: UITableViewController {
let musicArray = ["Old Town Road", "Starboy"]
var songName = ""
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return musicArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
cell.textLabel!.text = musicArray[indexPath.row]
//here is the problem
songName = cell.textLabel!.text!
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var vc = segue.destination as! ViewControllerOne
vc.songFinalName = self.songName
}
}
So I am doing music player App, but I don't know how to play current song. I have all songs in a row(identifier is MyCell). When I click on the cell named for example ,,Starboy" it should get that name and pass the data to the other VC and there play it, but always it only plays the latest thing that is in the raw, so for example there are 3 songs: Old Town Road, Starboy, Hello and it can play only the latest so in this example it is Hello. Can someone help me please? Thank you for reading.
You need to implement tableview's delegate method didSelectRowAt which will update the songName property whenever a user taps on any row of table view
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
songName = musicArray[indexPath.row]
}
Moreover, remove songName = cell.textLabel!.text! from cellForRowAt: indexPath method

How to maintain highlighted multiple UITableView rows after reloading UITableView?

I have a UITableView.
I can select multiple cells make them highlighted.
But, whenever I reload App, the selected and highlighted state disappears.
I think I need to put some codes in 'viewDidAppear' and 'didSelectRowAt'. But I don't have any idea of specific codes.
What do I have to put in this syntax?
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
I recommend u add to dataSource item field selected, and in method cellForRowAtindexPath configure by your dataSource items.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cellClass = (self.cellClass(for: indexPath) ?? self.cellClasses.first) else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: cellClass.identifier, for: indexPath)
if let configurable = cell as? ConfigurableComponent, let object = self.object(at: indexPath) {
let item = self.dataSource[indexPath.row]
configurable.selected = item.selected
}
return cell
}
When call didSelectRowAt, just take item and change selected field, sample:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = self.dataSource[indexPath.row]
item.selected = !item.selected
tableView.reloadData()
}

Swift adding clickable tableview

When I create a tableview, I cannot click on any of the items I put on the tableview. I was wondering how can I create a tableview that has every item clickable and when the user clicks on an item( say a city name, for example) it redirects the user to a different viewcontroller. ( for example if there are 22 clickable items in the tableview, there will be a total of 22 new different viewcontrollers )
Thank you very much in advance!
There are three major functions that a UITableViewDataSource must contain for the table view to work properly with user interaction (Pressing each row, for example). These functions are:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
The function you are looking to use is the third one. It is called when a user selects a certain row by tapping it on screen. You can find out the row index with 'indexPath'.
If you would like to go to 22 different view controllers, you need to create a manual segue between each one and label them accordingly. Then, you would want to call each individual segue depending on which row was selected inside of that third function! You can call a segue with an identifier with the performSegue() function.
Note that the class that contains these functions must be of type UITableViewDataSource, and you should tell the table view that it is the data source in the ViewDidLoad() function like so:
tableView.dataSource = self
Here is what a simple code can look like:
import UIKit
class viewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var identifiers = [String]()
override func viewDidLoad() {
// fill your identifiers here
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return 22
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellIdentifier") as! yourCell
// fill your cell's data in here
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
// here you can use someThing like an array of your segue identifiers
self.performSegue(withIdentifier: identifiers[indexPath.row], sender: self)
//Or you can just implement a switch with every case doing what you want that cell to do which i don't recommend if you have 22 rows
}
}

How to remove items from an array when deselecting a row in a UITableView

I'm trying to capture the selected items from a UITableView and save them into a new array. The following code creates the new array by adding the items when the rows is tapped, what it doesn't do is remove the items when the rows are deselected.
How can I remove items from the newFruitList when a row in a UITableView is deselected?
Or better yet, what is the proper way to generate an array of only the selected items in a UITableView?
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let fruits = ["Apples", "Oranges", "Grapes", "Watermelon", "Peaches"]
var newFruitList:[String] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = fruits[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
newFruitList.append(fruits[indexPath.row])
print("New List: \(newFruitList)")
}
#IBAction func makeSelection(_ sender: Any) {
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
}
You can just check whether the newFruitList contains the item you want to add by getting index of that item in your list.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
newFruitList.append(fruits[indexPath.row])
print("New List: \(newFruitList)")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let index = newFruitList.index(of: fruits[indexPath.row]) {
newFruitList.remove(at: index)
}
print("New List: \(newFruitList)")
}
It is pretty much the same as adding an element when you select a row:
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath {
newFruitList.remove(at: indexPath.row)
print("New List: \(newFruitList)")
}
You just have to use the didDeselectRowAt delegate method instead.
Update
As mentioned in the comments, this solution does not work since newFruitList does not necessarily have all of the original array elements. See the accepted answer instead.

didSelectRowAt indexPath does not when tapped (but does trigger when cell is swiped in either direction)

This is a weird (but should be simple) one. I am simply trying to tap a custom UITableViewCell and trigger a segue to go to another ViewController. didSelectRowAt indexPath does not trigger when the cell is tapped, but it oddly enough does when the cell is swiped from right to left or left to right.
My didSelectRowAt indexPath:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "mySegue", sender: self)
}
(as suggested here)
My ViewController:
import UIKit
class myViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDelegate {
var myData = NSDictionary()
override func viewDidLoad() {
super.viewDidLoad()
fetchMyData()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.rowHeight = 100
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func fetchMyData() {
// ... fetches my data
}
////////////////////////////////////////////////
//Table view data source
//set number of sections in table
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//set number of rows in table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
//delegate information to cells in table rows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("running tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell...")
// Dequeue cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! myCustomCell
cell.cellAmount!.text = "Hello World"
cell.cellTextField2!.text = "Some info"
cell.cellTextField3!.text = "Some other info"
cell.backgroundCardView.backgroundColor = UIColor.red
cell.backgroundCardView.layer.cornerRadius = 8.0
cell.backgroundCardView.layer.masksToBounds = false
cell.backgroundCardView.layer.shadowColor = UIColor.black.withAlphaComponent(0.9).cgColor
cell.backgroundCardView.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.backgroundCardView.layer.shadowOpacity = 0.9
print("finished tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell...")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "mySegue", sender: self)
}
// func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
// let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
// // delete item at indexPath
// }
// let share = UITableViewRowAction(style: .normal, title: "Disable") { (action, indexPath) in
// // share item at indexPath
// }
//
// share.backgroundColor = UIColor.blue
//
// return [delete, share]
// }
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
return []
}
// Reload the table data when a change is made
// func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
// self.tableView.reloadData()
// }
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
//Table view data source (end)
////////////////////////////////////////////////
}
I have already tried the following as well:
-didSelectRowAtIndexPath: not being called
How to detect Cell selection in UITableView - Swift
Push segue from UITableViewCell to ViewController in Swift
How to tap cell's buttons in UITableViewCell without actionning the cell's segue
is it possible to segue from a UITableViewCell on a UIView to another view
UITableView didSelectRowAt is not called iOS 10, but works for 9.3.5
The UITableViewCell does have UIView and multiple UITextFields, so I did make sure that User Interaction Enabled is unchecked for the UIView and UITextFields.
EDIT: I have also looked in the debugger navigator and can see that the CPU usage percentage increases when I tap a cell (). Maybe there is a way to step deeper and see why that tap doesn't then cause the didSelectRowAt indexPath to be triggered..?
Does anyone know what could possibly be causing didSelectRowAt indexPath to not be triggered when the cell is tapped?
I faced the same issue and found an answer that was applicable for me here. I had this code for keyboard dismiss in viewWillAppear:
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
After commenting this line tapping started to work! But now I will have to find better way for keyboard dismiss. :) Kindly check your exstensions, probably you used similar solution for keyboard dismiss.