Reputation: 1273
I have created an app to allow users to store various voice recordings against reviews. When I display this a table and the data is populated with the following code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let row = (indexPath as NSIndexPath).item
let cell = tableView.dequeueReusableCell(withIdentifier: "voiceRecordingCell", for: indexPath) as! VoiceRecordingTableViewCell
let voiceRecording = self.voiceRecordings[row] as! NSDictionary
let isoFormatter = DateFormatter()
isoFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'.000Z'"
let createdAt = isoFormatter.date(from: voiceRecording["created_at"] as! String)
self.recordingIndexPaths.insert(indexPath, at: row)
cell.recording = voiceRecording
cell.date.text = getDateFormatter("dd-MM-y").string(from: createdAt!)
cell.time.text = getDateFormatter("HH:mm").string(from: createdAt!)
cell.length.text = voiceRecording["length"] as? String
cell.location.text = voiceRecording["location"] as? String
let audioPlayerController = self.storyboard?.instantiateViewController(withIdentifier: "AudioPlayerController") as! AudioPlayerController
audioPlayerController.voiceRecording = voiceRecording
cell.audioPlayer.addSubview(audioPlayerController.view)
self.addChildViewController(audioPlayerController)
audioPlayerController.didMove(toParentViewController: self)
cell.deleteRecordingButton.tag = row
cell.deleteRecordingButton.addTarget(self, action: #selector(deleteRecordingPressed(_:)), for: .touchUpInside)
return cell
}
The cells all appear to be rendering correctly however for the cells that are not initially rendered with the page, the ones I have to scroll down to view, when I click on the buttons either on the audio player controls or the deleteRecordingButton
nothing happens, its as though the addTarget
is not being set. The code to set the buttons is being called and doesn't create an error, its just not applying to those button.
The buttons that are initially displayed on the screen have the correct actions and all work perfectly so I know that works.
I'm really at a loss as to what is causing this. I did try searching google and stackoverflow but I've not found anything. Any assistance with this would be greatly received.
--------------- UPDATE -----------
I just tried putting some breakpoints in
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
That also only works get called on the top 2 cells or the top one if in landscape!
Upvotes: 0
Views: 829
Reputation: 1273
Finally I have figured this out...
This was happening because I was using a scrollview with to scroll up and down the table without using the tables native scroll functionality.
When using the tables scroll functionality the buttons are applied the actions as they are brought into the view. This is handled by the func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
method. However when you do it the way I was it initially renders all the cells and the ones that are off the screen don't work!
Its a little bit annoying working in this way but at least I now know about it.
Upvotes: 0
Reputation: 76
Since the cell gets reused all the time the reference get lost. Try something like this:
class ButtonTableViewCell: UITableViewCell {
typealias TapClosure = () -> Void
var buttonTapped: TapClosure?
@IBAction func buttonTouchUpInside(sender: UIButton) {
buttonTapped?()
}
}
extension TestViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! ButtonTableViewCell
cell.buttonTapped = {
print("Button tapped")
}
return cell
}
}
And another tipp. Never init an DateFormatter
in cellForRowAtIndexPath. Instead create it in viewDidLoad or in a static struct for reuse.
Upvotes: 2