Reputation: 35
I am attempting to create a table view with multiple Custom UITableViewCells. If I only use one custom cell the correct cell is displayed. If I add my second cell, The display second cell overwrites the first and inhibits interaction, and the second cell displays default data of the first custom cell until it is selected then it displays the correct cell.
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let nib1 = UINib(nibName: "AccountCell1", bundle: nil)
tableView.registerNib(nib1, forCellReuseIdentifier: "SettingCell1")
let nib2 = UINib(nibName: "AccountCell2", bundle: nil)
tableView.registerNib(nib2, forCellReuseIdentifier: "SettingCell2")
//removing empty rows
tableView.tableFooterView = UIView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
/*let cell = tableView.dequeueReusableCellWithIdentifier( "AccountCell", forIndexPath: indexPath) as! UITableViewCell*/
let cell1 = tableView.dequeueReusableCellWithIdentifier( "SettingCell1", forIndexPath: indexPath) as! AccountCell1Controller
let cell2 = tableView.dequeueReusableCellWithIdentifier( "SettingCell2", forIndexPath: indexPath) as! AccountCell2Controller
// Configure the cell...
if(indexPath.row == 0)
{
let imageName = "Amanda.jpeg"
let image = UIImage(named: imageName)
cell1.UserImage.image = image
cell1.UserLabel.text = "@AmandaSmith"
cell1.setNeedsLayout()
return cell1
}
else
{
return cell2
}
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if(section == 0)
{
return "John Smith"
}
else if(section == 1)
{
return "Settings"
}
else if(section == 2)
{
return "About"
}
return ""
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(indexPath.row == 0)
{
return 204
}
else if(indexPath.row == 1)
{
return 61
}
else {
return 44
}
}
}
My Account cell controllers, 2 is two buttons with corresponding actions
class AccountCell1Controller: UITableViewCell {
@IBOutlet weak var UserImage: UIImageView!
@IBOutlet weak var UserLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
let user = UserData.self
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Upvotes: 2
Views: 3107
Reputation: 2519
The issue is that you're dequeuing cell1
even when you're not making a cell for that row.
Try only dequeuing the cell that you actually need for the given indexPath.row
:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Configure the cell...
if(indexPath.row == 0) {
let cell1 = tableView.dequeueReusableCellWithIdentifier( "SettingCell1", forIndexPath: indexPath) as! AccountCell1Controller
let imageName = "Amanda.jpeg"
let image = UIImage(named: imageName)
cell1.UserImage.image = image
cell1.UserLabel.text = "@AmandaSmith"
cell1.setNeedsLayout()
return cell1
} else {
let cell2 = tableView.dequeueReusableCellWithIdentifier( "SettingCell2", forIndexPath: indexPath) as! AccountCell2Controller
return cell2
}
}
To understand why dequeuing breaks things, it's important to understand how a TableView works.
Let's say you have 100 cells in a table. It would be wasteful to create and manage all 100 of those cells, if your device (say iPhone) can only display 10 at a time. Dequeuing works based on this principle, that you only need about as many cells allocated, as you're ever going to display. So each time you need a new cell (each time cellForRowAtIndexPath
is called) you only want to dequeue the cell type that you need, and if a cell is leaving the screen at the same time, you can reuse it, instead of deleting it and going through the (potentially) heavy process of creating a new cell.
Knowing this, I'm still a little hazy on why dequeuing two cells for a single index breaks the layout, but it clearly confused the TableView. As a general rule of thumb when dealing with multiple custom cells in a single tableView, it's best to split out cellForRowAtIndexPath
into separate functions for each type of cell (and possibly for different sections as well, if that makes sense). This way you can switch
on indexPath.row
and call your own custom dequeueThisSettingsCell
or dequeueOtherSettingsCell
depending on the row, returning the cell back to cellForRowAtIndexPath
which then returns it to the tableView. This also greatly shortens cellForRowAtIndexPath
, making it clear what kind of cell is dequeued for what row/section, and separates the setup of each cell into different functions (which helps with clarity and readability).
Upvotes: 1