Add target to cell but having local variables create issues swift - swift

I have a custom cell class. I have a button in a cell to which I have to add a target. But to do so, I have to implement a function for the action with the #objc keyword which I can't do as a nested function. Yes I have to make nested functions because of local variables such as indexPath and cell. Thanks
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "itemCellSub", for: indexPath) as! newInvoicePopup_ItemTableViewCell
cell.textLabel!.text = (filteredItems[indexPath.row] as! ItemData).name
cell.detailTextLabel!.text = (filteredItems[indexPath.row] as! ItemData).tax
cell.priceLabel!.text = (filteredItems[indexPath.row] as! ItemData).price
cell.addButton.addTarget(self, action: #selector(connected(sender:)), for: .touchUpInside)
return cell
}

Related

Crash: Attempted to dequeue multiple cells for the same index path, which is not allowed

I have tableview datasource func to build a cell from a factory method function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return OWTableViewOrganizer.instance.configureCell(at: indexPath)!
}
The factory method is here:
func configureCell(at indexPath: IndexPath) -> UITableViewCell? {
var cell = UITableViewCell()
switch indexPath.section {
case thisWorkoutSections.barbel.sectionNumber():
cell = barebellCell(indexPath: indexPath)
break
case thisWorkoutSections.lastWorkout.sectionNumber():
cell = lastWorkoutCell(indexPath: indexPath)
break
case thisWorkoutSections.personalRecord.sectionNumber():
cell = personalRecordCell(indexPath: indexPath)
break
case thisWorkoutSections.notes.sectionNumber():
break
default:
break
}
return cell
}
I have this code to build the cell:
func lastWorkoutCell(indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
if OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count > 0 {
if indexPath.row < OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count {
let logExerciseSet = OWTableViewOrganizer.instance.lastWorkoutExerciseSets[indexPath.row]
let setNumber = indexPath.row + 1
if let weight = logExerciseSet.weight?.doubleValue, let reps = logExerciseSet.reps?.intValue {
cell.setupCellWithData(setNumber: setNumber, weight: weight, reps: reps)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
return cell
}
But time to time this line crashes for me:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
With error:
Attempted to dequeue multiple cells for the same index path, which is not allowed. If you really need to dequeue more cells than the table view is requesting, use the -dequeueReusableCellWithIdentifier: method (without an index path)
I know code style and design is not ideal here, please skip this if you have comments.
I don't know where to look, I tried simply remove indexPath, but it looks does not help or bring even more issues:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier()) as! WorkoutSetTableViewCell
I have one controller which presents another one at the top of it (like in Apple music) and I can swipe down to show bottom controller and swipe up to bring back top controller. I noticed in log that I have some presentation alert, not sure if this something I need to deal with to resolve the issue above but JFY info.
It seems like there are two table view trigger
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
and you only dequeue cell from 1 table view at
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
You should try to pass tableView from
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
to
lastWorkoutCell(indexPath: IndexPath)
(which will become lastWorkoutCell(indexPath: IndexPath, tableView: UITableView)) and dequeue cell from tableView

Change selected cell image uitableview

I want to change cell image when music is playing , I am using didselectrow for this when i select row it change image and when i scroll i see many other cell image is also changed i don't why please guide me
here is my code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
}
try:
var isPlayingIndex = -1
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
if indexPath.row == isPlayingIndex {
cell?.btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}else {
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? NaatListTableViewCell
if indexPath.row == isPlayingIndex {
cell?.btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
isPlayingIndex = -1
} else {
// stop current player
//
isPlayingIndex = indexPath.row
cell?.btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}
}
Instead of changing the image in didSelectRowAt method, you can do it another way by implementing setSelected(_:animated:) method in your custom UITableViewCell and handle the image status there, i.e.
override func setSelected(_ selected: Bool, animated: Bool) {
if selected {
btnPlayPause.setImage(UIImage(named: "pause"), for: .normal)
} else {
btnPlayPause.setImage(UIImage(named: "play"), for: .normal)
}
}
The above method handles the selection and de-selection for all the cells in the tableView in single-selection and multi-selection modes.
After this, you'll not need to write anything in tableView(_:didSelectRowAt:) method.
You need to maintain state for your cell manually. You might have some other data associated with your cell, from what you have asked it seems like a list of music files, you could associate with each music a unique id in its model. Now create a map of type var isPlaying = [Int: Bool]() (assuming you are going with int ids)
Then in didSelectRowAt set the value with corresponding id
self.isPlaying[YOUR_ID] = cell.isSelected
Now in your cellForRowAt method
var imageName = self.isPlaying[YOUR_ID] ? "play" : "pause"
cell?.btnPlayPause.setImage(UIImage(named: imageName), for: .normal)

Swift tableview cell doesn't save the state with different identifier

I am very confused on the reuse of the cells.
I have a table, each cell is a cell with a switch on it. If I toggle a switch I set the background color of that cell to a different color. However every time I scroll these changes don't persist.
I am subclassing UITalbeViewCell to create my own custom cell. Each cell has a different identifier. However when I scroll through the table, whatever changes I made to the cell still doesn't save. I've read similar questions but none of them worked.. Some suggested subclass which I did, some suggested use different identifier which I also did...
Here is the code of my tableview.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let key = Array(dataSource[indexPath.section].keys)[indexPath.row]
let cell = CellWithSwitch.init(style: .subtitle, reuseIdentifier: key)
cell.awakeFromNib()
let val = Array(dataSource[indexPath.section].values)[indexPath.row]
cell.switchView?.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
if let index = key.firstIndex(of: "."){
cell.textLabel?.text = String(key.suffix(from: key.index(index, offsetBy: 1)))
}else{
cell.textLabel?.text = key;
}
cell.switchView?.setOn(val, animated: true)
return cell
}
You can change array value in switchChange action
lets i take array for switch as below:
var arrSwitch = [false,false,false,false,false,false,false,false,false,false]
Below is my cellForRowAt Method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! customCell
cell. switchView.setOn(self.arrSwitch[indexPath.row], animated: false)
cell. switchView.tag = indexPath.row
cell. switchView.addTarget(self, action: #selector(self.onSwitchTap(_:)), for: .valueChanged)
return cell
}
Here is my onSwitchTap Action
#IBAction func onSwitchTap(_ sender: UISwitch) {
self.arrSwitch[sender.tag] = !self.arrSwitch[sender.tag]
}
Now on scroll it will persist last changes you have done.

Editor placeholder in source file error with simple UITableView

I am totally new to Swift and also have no background experience in development. I am trying to a simply table view in Swift but keep getting the error 'Editor placeholder in source file.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: <#T##IndexPath#>) as! CustomCell
cell.photo.image = images[indexPath.row]
cell.Name.text = names[indexPath.row]
cell.Job.text = jobs[indexPath.row]
return cell
}
This is where your problem is:
for: <#T##IndexPath#>)
just tab to that variable and type in:
indexPath

Using UITableView and IndexPath with Swift 3 shows an error

I have this code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: IndexPath) as? Cell
But IndexPath is showing an error:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: IndexPath) as? Cell
In this line you're passing IndexPath Class instead of the indexPath parameter from the function. replace it with:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? Cell