12

I currently have a UITableView containing 2 rows of a custom cell. I recently added a second prototype cell to my storyboard and have been attempting to add it to my UITableView with no success. My cellForRowAtIndexPAth method is as follows:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell: FlightsDetailCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as FlightsDetailCell

    cell.userInteractionEnabled = false

    if indexPath.section == 0 {

        cell.graphView.enableBezierCurve = true
        cell.graphView.enableReferenceYAxisLines = true
        cell.graphView.enableYAxisLabel = true
        cell.graphView.colorYaxisLabel = UIColor.whiteColor()
        cell.graphView.delegate = UIApplication.sharedApplication().delegate as BEMSimpleLineGraphDelegate
        cell.graphView.dataSource = UIApplication.sharedApplication().delegate as BEMSimpleLineGraphDataSource
        return cell
    }

    if indexPath.section == 1 {
        cell.graphView.enableBezierCurve = true
        cell.graphView.enableReferenceYAxisLines = true
        cell.graphView.enableYAxisLabel = true
        cell.graphView.colorYaxisLabel = UIColor.whiteColor()
        cell.graphView.delegate = self
        cell.graphView.dataSource = self
        return cell
    }

    if indexPath.section == 2 {

        let cell2: FlightsInformationCell = tableView.dequeueReusableCellWithIdentifier("Cell2", forIndexPath: indexPath) as FlightsInformationCell
        cell2.userInteractionEnabled = false

        return cell2
    }

    return cell

}

Section 0 and Section 1 correctly load the prototype cell with ID "Cell" but when I go to load section 2 I get another instance of the first prototype cell less any data as it hasn't been assigned a delegate or dataSource. Otherwise the cells are set up identically with ID's of "Cell" and "Cell2" respectively but I can't seem to access "Cell2".

Additional Clarification: I have 2 prototype cells in my storyboard, they are both set up the same in that they both have their identifiers labeled in the same boxes, inherit from their own classes and have been declared the same in my UITableView. As for the delegates and dataSources, my original prototype cell holds a graph (uses BEMSimpleLineGraph), each instance of this cell has it's own delegate and datasource and shown in the above code for actions 0 and 1.

The first cell pictured below (in grey) is the original cell that holds a graph and cell2 is just below it in white.

enter image description here

Sam Spencer
  • 8,492
  • 12
  • 76
  • 133
user3185748
  • 2,478
  • 8
  • 27
  • 43
  • dunno how to handle this in swift, but you should probably refactor your code such that you declare `cell` but don't actually instantiate/assign it to a non-nil value until the code inside of the if/else statement is executed. your if/else should be more like `if(indexPath.section < 2){ cell = cell1 }else{ cell = cell2 } return cell` – Louis Tur Jan 16 '15 at 22:07
  • Interesting, now would that be functionally any different than what I'm currently doing? Given that as soon as a `return` is passed the method will exit anyways? – user3185748 Jan 16 '15 at 22:15
  • have you checked that `cell2` is created? (i.e. that you enter the if branch?) I suspect it is not, so you just return the `cell` object you created at the start of the method – sergio Jan 16 '15 at 22:21
  • best practices and readability. I find code refactoring is also calming :) Also, are you subclassing these two cells as well? I just noticed you have them as what appears to be two classes. – Louis Tur Jan 16 '15 at 22:23
  • They are both indeed declared in 2 classes, I hope to clean everything up once I've got this working haha. Also `cell2` is indeed created. – user3185748 Jan 16 '15 at 22:26
  • You need to better explain what the problem is. Do you actually get a FlightsInformationCell? You say they're "set up identically", what does that mean? Do the cells look alike? Your statement about the delegate and data source doesn't make any sense -- those things are set for the table view, not on a per cell basis. – rdelmar Jan 16 '15 at 22:29
  • I have updated my post with additional information. – user3185748 Jan 16 '15 at 22:33
  • @user3185748: Post a screenshot of your cells and their identifiers. Also put a NSLog on the indexPath.section == 2 case and check whether it is calling or not – Midhun MP Jan 16 '15 at 22:36
  • I'm guessing that you never enter your ndexPath.section == 2 clause, and you're returning (with that last line) the cell you dequeue as the first line in cellForRowAtIndexPath. As was stated before, that dequeue method should be inside an if-else clause. – rdelmar Jan 16 '15 at 22:38
  • I have checked and `indexPath.section == 2` is called. I have updated my original post to include a screenshot of the prototype cells, the second cell is selected and the `Cell2` identifier is visible in the attributes inspector, the first cell is the same except the identifier is `Cell` – user3185748 Jan 16 '15 at 22:39
  • I tried running the app with breakpoints at `return cell` (Under Section 0), `return cell` (Under Section 1), and `return cell2` (Under Section 2). The first breakpoint was triggered, when I continued the second was triggered, finally `return cell2` was triggered and when I continued the app the UITableView was visible. correct me if I'm wrong but this suggests to me that the case statements are doing their job, no? – user3185748 Jan 16 '15 at 22:45
  • your Cell2 prototype cell, have you made sure to set it to be a `FlightsInformationCell` class In the Identity Inspector? – Louis Tur Jan 16 '15 at 22:45
  • Is your data source returning 3 sections only? Could you be seeing an empty FlightsInformationCell, followed by another FlightsDetailCell (this would only happen if you're returning 4 for number of sections)? – rdelmar Jan 16 '15 at 22:46
  • Yes, it is set to this class. – user3185748 Jan 16 '15 at 22:46
  • numberOfSectionsInTableView is set to 3, and numberOfRowsInSection is set to 1 for all sections. – user3185748 Jan 16 '15 at 22:48
  • try calling your cells via their `cellWithIdentifier:` rather than `cellWithIdentifier:atIndexPath:`. Reason being, the documentation for UITableView says >"You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method." Im not sure that IB does that.. it might, but Im not sure – Louis Tur Jan 16 '15 at 23:17

1 Answers1

18

I set up a test app using code similar to what you have in cellForRowAtIndexPath, and I got the same results. Even though the code in my if indexPath.section == 2 clause was entered, the cell that was returned looked the same as my first two cells (but with no string in the label); this is despite the fact that I set it up with different sub views, and a log showed it to be the correct class for what I wanted for section 2. Why this happens, I don't know, but to fix it what you need to do is to dequeue the cell inside your if blocks like so.

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {


cell.userInteractionEnabled = false

if indexPath.section == 0 {
    let cell: FlightsDetailCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as FlightsDetailCell
    cell.graphView.enableBezierCurve = true
    cell.graphView.enableReferenceYAxisLines = true
    cell.graphView.enableYAxisLabel = true
    cell.graphView.colorYaxisLabel = UIColor.whiteColor()
    cell.graphView.delegate = UIApplication.sharedApplication().delegate as BEMSimpleLineGraphDelegate
    cell.graphView.dataSource = UIApplication.sharedApplication().delegate as BEMSimpleLineGraphDataSource
    return cell
}

else if indexPath.section == 1 {
    let cell: FlightsDetailCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as FlightsDetailCell
    cell.graphView.enableBezierCurve = true
    cell.graphView.enableReferenceYAxisLines = true
    cell.graphView.enableYAxisLabel = true
    cell.graphView.colorYaxisLabel = UIColor.whiteColor()
    cell.graphView.delegate = self
    cell.graphView.dataSource = self
    return cell
}

else {
    let cell2: FlightsInformationCell = tableView.dequeueReusableCellWithIdentifier("Cell2", forIndexPath: indexPath) as FlightsInformationCell
    cell2.userInteractionEnabled = false
    return cell2
}

}

This could be further refactored to take out repetitive code, but this should work...

needshelp
  • 595
  • 1
  • 6
  • 25
rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Thanks for the reply, that turns out to be close but for some reason my third cell has the right contents but has the same row height as `cell` rather than my `cell2`. For the moment I have corrected that using a `heightForRowatIndexPath` method although it seems a bit off to me. Otherwise thanks so much for the help! – user3185748 Jan 17 '15 at 14:38
  • While your solution works, I think there could be a way to avoid so much redundant code. Were you able to find a better solution? – Marcus Feb 12 '16 at 02:10