I have a pretty complicated table view setup and I resolved to use a block structure for creating and selecting the cells to simplify the future development and changes.
The structure I'm using looks like this:
var dataSource: [(
cells:[ (type: DetailSection, createCell: ((indexPath: NSIndexPath) -> UITableViewCell), selectCell: ((indexPath: NSIndexPath) -> ())?, value: Value?)],
sectionHeader: (Int -> UITableViewHeaderFooterView)?,
sectionFooter: (Int -> UITableViewHeaderFooterView)?
)] = []
I can then set up the table in a setup function and make my delegate methods fairly simple
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = dataSource[indexPath.section].cells[indexPath.row].createCell(indexPath:indexPath)
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource[section].cells.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return dataSource.count
}
I have made a similar setup before in another TVC
var otherVCDataSource: [[ (type: DetailSection, createCell: ((indexPath: NSIndexPath) -> UITableViewCell), selectCell: ((indexPath: NSIndexPath) -> ())?)]] = []
This solution has worked great.
The current dataSource with the sectionHead and footer however gives me a EXC_BAD_ACCESS every time I try to access the indexPath in one of the createCell blocks.
createCell: {
(indexPath) in
let cell:CompactExerciseCell = self.tableView.dequeueReusableCellWithIdentifier(self.compactExerciseCellName, forIndexPath:indexPath) as! CompactExerciseCell
cell.nameLabel.text = "\(indexPath.row)"
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
The app always crashes on
self.tableView.dequeueReusableCellWithIdentifier(self.compactExerciseCellName, forIndexPath:indexPath)
What am I missing here? Why can't I access the indexPath in the new structure when it works fine in the old structure? What is different in the memory management between this tuple and the array?
UPDATE:
So I had a deadline to keep and I finally had to give up and rework the data structure.
My first attempt was to instead of sending the indexPath as a parameter send the row and section and rebuild an indexPath inside the block. This worked for everything inside the data structure but if I pushed another view controller on a cell click I got another extremely weird crash (some malloc error, which is strange as I use ARC) when dequeuing cells in the next VC.
I tried to dig around in this crash as well but there was no more time to spend on this so I had to move on to another solution.
Instead of this tuple-array [([],,)] I made two arrays; one for the cells and one for the headers and footers. This structure removed the problem of the indexPath crash but I still had the issue in the next VC that didn't stop crashing when dequeueing the cells.
The final solution, or workaround, was to access the cell creator and selector "safely" with this extension:
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
basically the return statement in the tableView delegate functions then looks like this:
return dataSource[safe:indexPath.section]?[safe:indexPath.row]?.createCell?(indexPath: indexPath)
instead of
return dataSource[indexPath.section][indexPath.row].createCell?(indexPath: indexPath)
I can't see how it makes any difference to the next VC as the cell shouldn't even exist if there was an issue with executing nil or looking for non existing indexes in the data structure but this still solved the problem I was having with the dequeueing of cells in the next VC.
I still have no clue why the change of data structure and the safe extension for getting values from an array helps and if someone has any idea I would be happy to hear it but I can not at this time experiment more with the solution. My guess is that the safe access of the values reallocated the values somehow and stopped them from being released. Maybe the tuple kept the compiler from understanding that the values should be kept in memory or maybe I just have a ghost in my code somewhere. I hope one day I can go back and dig through it in more detail...