I implemented an NSFetchedResultsController
on a UITableView
in a Core Data project in Swift 2.0. Additionally, I have a UISearchController
implemented. Everything works perfectly with the exception of the behavior I'm encountering on my custom UITableViewCell
buttons.
When UISearchController
is active, the customTableViewCell
's buttons work as they should. If I click the same button when the fetchedResultsController
is displaying its results, the method thinks Index 0 is the sender, regardless of which button I click.
func playMP3File(sender: AnyObject) {
if resultsSearchController.active {
// ** THIS WORKS **
// get a hold of my song
// (self.filteredSounds is an Array)
let soundToPlay = self.filteredSounds[sender.tag]
// grab an attribute
let soundFilename = soundToPlay.soundFilename as String
// feed the attribute to an initializer of another class
mp3Player = MP3Player(fileName: soundFilename)
mp3Player.play()
} else {
// ** THIS ALWAYS GETS THE OBJECT AT INDEX 0 **
let soundToPlay = fetchedResultsController.objectAtIndexPath(NSIndexPath(forRow: sender.tag, inSection: (view.superview?.tag)!)) as! Sound
// OTHER THINGS I'VE TRIED
// let soundToPlay = fetchedResultsController.objectAtIndexPath(NSIndexPath(forRow: sender.indexPath.row, inSection: (view.superview?.tag)!)) as! Sound
// let soundToPlay: Sound = fetchedResultsController.objectAtIndexPath(NSIndexPath(index: sender.indexPath.row)) as! Sound
let soundFilename = soundToPlay.soundFilename as String
mp3Player = MP3Player(fileName: soundFilename)
mp3Player.play()
}
}
Here's an abbreviated version of my cellForRowAtIndexPath
to show I'm setting up the cells' buttons:
let customCell: SoundTableViewCell = tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! SoundTableViewCell
if resultsSearchController.active {
let sound = soundArray[indexPath.row]
customCell.playButton.tag = indexPath.row
} else {
let sound = fetchedResultsController.objectAtIndexPath(indexPath) as! Sound
customCell.playButton.tag = indexPath.row
}
// add target actions for cells
customCell.playButton.addTarget(self, action: "playMP3file:", forControlEvents: UIControlEvents.TouchUpInside)
I've tried a few other approaches I've found here, such as translating CGPoints
to IndexPaths
, etc. without much luck. Everything that looked promising in the compiler crashed when I clicked the button in the simulator.
Thank you for reading.
Update Installed Xcode 7.1, rebooted, cleaned caches, nuked derived data, did a cold boot.
Solution
Tags will get the job done in many cases (such as getting the location in an Array
) and get lots of votes here, but as I've learned, they don't work all the time. Thank you to Mundi for pointing me towards a more robust solution.
// this gets the correct indexPath when resultsSearchController is not active
let button = sender as! UIButton
let view = button.superview
let cell = view?.superview as! SoundTableViewCell
let indexPath: NSIndexPath = self.tableView.indexPathForCell(cell)!
let soundToPlay = fetchedResultsController.objectAtIndexPath(indexPath) as! Sound
I've tried a few other approaches I've found here, such as translating CGPoints to IndexPaths, etc. without much luck.
Translating points is indeed the most robust solution. This answer contains the correct code.