Rico
Rico

Reputation: 59

Swift TableView with multiple prototype cells are not displaying all Rows

I have a UITableView created with 2 prototype cells, each of which have separate identifiers and subclasses.

My problem is when I display the cells the second prototype's first row gets absorbed under the first prototype cell.

For example, I have the first prototype cell displaying only 1 item. The second prototype cell should display 4 items. But, the first item from the second prototype cell is not displaying and, instead, there are only 3 of the four items visible.

Here is the code I have implemented:

  override func viewDidLoad() {
 super.viewDidLoad()


    self.staticObjects.addObject("Please...")
    self.objects.addObject("Help")
    self.objects.addObject("Me")
    self.objects.addObject("Thank")
    self.objects.addObject("You")

    self.tableView.reloadData()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return self.objects.count
}

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

   if(indexPath.row==0){

         let staticCell = self.tableView.dequeueReusableCellWithIdentifier("staticCell", forIndexPath: indexPath) as! StaticTableViewCell

         staticCell.staticTitleLabel.text = self.staticObjects.objectAtIndex(indexPath.row) as? String

        return staticCell

    }

    else{

        let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PillarTableViewCell

        cell.titleLabel.text = self.objects.objectAtIndex(indexPath.row) as? String


        return cell

    }

Thanks for all the help.

Upvotes: 1

Views: 2807

Answers (1)

whyceewhite
whyceewhite

Reputation: 6435

You have logic issues with how you are counting the number of rows in your table for both tableView:numberOfRowsInSection and tableView:cellForRowAtIndexPath.

Your code is producing a display output as shown below where:

  • The blue cells represent your staticCell prototype table cell view; these are the values from the staticsObjects array.
  • The yellow cells represent your cell prototype table cell view; these are the values from the objects array.

Bad Output of Table View


1. Look at tableView:cellForRowAtIndexPath:

In the cellForRowAtIndexPath method, you are only returning the count of the objects array.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {        
    return self.objects.count
}

That means that the number of rows you will have in your table will be 4 instead of 5. Instead, you want to return the sum of the two arrays you are using in your table: objects.count + staticObjects.count. For example:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return objects.count + staticObjects.count
}

2. Look at tableView:cellForRowAtIndexPath:

Here's your original code with my comments..

// You are assuming that `staticObjects` will always have 
// exactly one row. It's better practice to make this
// calculation more dynamic in case the array size changes.
if (indexPath.row==0){

    let staticCell = self.tableView.dequeueReusableCellWithIdentifier("staticCell", forIndexPath: indexPath) as! StaticTableViewCell
    staticCell.staticTitleLabel.text = self.staticObjects.objectAtIndex(indexPath.row) as? String
    return staticCell            
} else {            
    let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PillarTableViewCell
    // Here's your problem! You need to calculate the row
    // because you want to put the objects from your other
    // array first. As a result, you need to account for them.
    cell.titleLabel.text = self.objects.objectAtIndex(indexPath.row) as? String
    return cell     
}

Now, here's one way to fix your errors stated in the above discussion:

// If the indexPath.row is within the size range of staticObjects
// then display the cell as a "staticCell".
// Notice the use of "staticObjects.count" in the calculation.
if indexPath.row < staticObjects.count {
    let staticCell = self.tableView.dequeueReusableCellWithIdentifier("staticCell", forIndexPath: indexPath) as! StaticTableViewCell
    staticCell.staticTitleLabel.text = self.staticObjects.objectAtIndex(indexPath.row) as? String
    return staticCell
} else {
    // If you get here then you know that your indexPath.row is
    // greater than the size of staticObjects. Now you want to
    // display your objects values.
    // You must calculate your row value. You CANNOT use the
    // indexPath.row value because it does not directly translate
    // to the objects array since you put the staticObjects ahead
    // of them. As a result, subtract the size of the staticObjects
    // from the indexPath.row.        
    let row = indexPath.row - staticObjects.count
    let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! PillarTableViewCell
    cell.titleLabel.text = self.objects.objectAtIndex(row) as? String                  
    return cell
}

Now you should see this:

Correct Display of Table View

Upvotes: 1

Related Questions