didSelectRowAtIndexPath returns wrong row index inconsistently - ios

I have a table view with rows, and when clicking on the row, sometimes it returns the row that is up one position from the one I clicked. The relevant code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell: UITableViewCell = self.tableView.cellForRowAtIndexPath(indexPath)!
currentCell.backgroundColor = UIColor.greenColor()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell")!
//.... cell modifications
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// this is to make at least one empty row
if (meeting.attendees.isEmpty) {
return 1
} else {
if section == 0 {
return requiredParticipants.count }
else {
return optionalParticipants.count }
}
}
What did I do to address the issue:
1. checked the consistency of arrays with the numberOfRows function (it's correct, the number is right)
2. checked the height of the cell - suspected the upper cell to overlap somehow the bottom cell - also not the case
3. refactored cellForRow to use dequeReusableCell (was not used initially) - suspected the memory issue, also did not help.
What happens: when you click, the cell that is clicked is highlighted with the green light, and approx. 50% of the time, the cell one position up from the one you click gets highlighted. The issue is also inconsistent, meaning that half of the time the right one is highlighted.

Related

Give different number of Rows for multiple cells in UITableView

Hello,
i have created a UITableView in which it has two different cells DynamicFormCell and StaticFormCell, so the DynamicFormCell can be displayed number of times i have a data from a server telling me how many forms i need for the DynamicFormCell and the StaticFormCell is always the same and doesn't change so i am having difficulty giving different number of rows for each cell.i tried giving the two cell a tag of 0 and 1 respectively and used this code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(tableView.tag == 0){
return 5//return five dynamic cells
}
if(tableView.tag == 1){
return 1//return one static cell
}
}
but this doesn't work and i also tried removing all the tags and if statements in the above code and just doing this return 5 this just gave me one DynamicFormCell and five StaticFormCells.
i also gave different classes for the two cells so i can assign them separately:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row == 0){
//firstRow make dynamic
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicFormsCell") as! DynamicFormsCell
return cell
}else{
//static form data
let cell = tableView.dequeueReusableCell(withIdentifier: "StaticFormsCell") as! StaticFormsCell
return cell
}
}
so my question is, is it possible to do this using table views and how can i do it? if not what other options do i have?
Yes it is possible to have multiple types of cell in single tableview. It has nothing to do with function
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
You should return there cells as,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (count of dynamic cells + count of static cells)
}
I assume, you only have to display static cells in the bottom. So if there are total 5 cells then 4 cells are dynamic and 5th cell would be static.
So code for, cellForRowAt indexPath: will be,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row < (count for dynamic cells)){
//first 4 Rows make dynamic
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicFormsCell") as! DynamicFormsCell
return cell
}else{
//last row static form data
let cell = tableView.dequeueReusableCell(withIdentifier: "StaticFormsCell") as! StaticFormsCell
return cell
}
}
What you're doing right now is checking if the TableView's tag is 0 or 1. Which is not you want to do, since you're using only one TableView.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (amount of DynamicCellsYouWant + amount of StaticCellsYouWant)
}
The second part of your code only works when you want the first cell to be a DynamicFormsCell and the rest to be a StaticFormsCell.

tableView data gets reloaded every time I scroll it

So every time I scroll my tableView it reloads data which I find ridiculous since it makes no sense to reload data as it hasn't been changed.
So I setup my tableView as follows:
func numberOfSections(in tableView: UITableView) -> Int {
return self.numberOfElements
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 6
}
My cells are really custom and they require spacing between them. I couldn't add an extra View to my cell to fake that spacing because I have corner radius and it just ruins it. So I had to make each row = a section and set the spacing as a section height.
My cell has a dynamic height and can change it's height when I click "more" button, so the cell extends a little.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if self.segmentedControl.selectedSegmentIndex == 0 {
if self.isCellSelectedAt[indexPath.section] {
return self.fullCellHeight
} else {
return self.shortCellHeight
}
} else {
return 148
}
}
And here's how I setup my cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if self.segmentedControl.selectedSegmentIndex == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(CurrentDocCell.self)) as! CurrentDocCell
(cell as! CurrentDocCell).delegate = self
(cell as! CurrentDocCell).ID = indexPath.section
} else {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(PromissoryDocCell.self)) as! PromissoryDocCell
}
return cell
}
So I have a segmentedControl by switching which I can present either one cell of a certain height or the other one which is expandable.
In my viewDidLoad I have only these settings for tableView:
self.tableView.registerCellNib(CurrentDocCell.self)
self.tableView.registerCellNib(PromissoryDocCell.self)
And to expand the cell I have this delegate method:
func showDetails(at ID: Int) {
self.tableView.beginUpdates()
self.isCellSelectedAt[ID] = !self.isCellSelectedAt[ID]
self.tableView.endUpdates()
}
I set a breakpoint at cellForRowAt tableView method and it indeed gets called every time I scroll my tableView.
Any ideas? I feel like doing another approach to make cell spacing might fix this issue.
A UITableView only loads that part of its datasource which gets currently displayed. This dramatically increases the performance of the tableview, especially if the datasource contains thousands of records.
So it is the normal behaviour to reload the needed parts of the datasource when you scroll.

Index out of range in cell of UITableViewController - swift

I have a UITableViewController. In the code of the tableview I want to display a "lineLabel" (which is just a blank label with a background at the bottom of the cell), if a value is equal to another value - and I got that working pretty nice!
The problem is that when I reach the bottom cell I get the index out of range error. I know why I get the error (will show you in code), but I do not know how to prevent that error and still get the same result as I do now?
Hope you can help me!
Here is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:carTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! carTableViewCell
let checkBackgroundColor = carsArray[indexPath.row + 1].componentsSeparatedByString("#")
if checkBackgroundColor[4] == finalCars[4] {
cell.lineLabel.hidden = true
} else {
cell.lineLabel.hidden = false
}
return cell
}
I get the index out of range error, because I am checking for an index that isn't there, in the workoutsArray[indexPath.row + 1].componentsSeparatedByString("#") part of my code. I just do not know how to do this otherwise? Anyone??
Check an array count before:
if carsArray.count > indexPath.row + 1 {
// your code here
}
but also you MUST do the proper calculations of your tableview rows count and put it inside your override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int

Why repeated cells show up in UITableView?

Now why would repeated cells show up in a UITableView ?
As you can see in this GIF, I press on a cell button to do some fade effect, but other cell gets affected too !
https://media.giphy.com/media/xT0BKL5KnCgEjaXm9i/giphy.gif
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return numberOfCells
}
and the count of cells is always 10
numberOfCells = 10
I always make tableviews and I'm sure of the setup, is this a bug by apple's side?
EDIT :
How the cells get created:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("brandCell", forIndexPath:indexPath) as! CustomCell1INF
cell.selectionStyle = UITableViewCellSelectionStyle.None
cell.frame = self.view.frame
return cell
}
This happens because the UITableViewCell are being reused.
You changed the cell when you press the button, you need to keep track of that in your data source model.
In cellForRowAtIndexPath you have to add a condition to check if that button was pressed or not, then you display the appropriate view accordingly.

Hide a cell in static tableview section

I'm trying to do something I would expect to be simplistic, but it's escaping me. I'm trying to show\hide the LAST cell in a tableview section. If I create an IBOutlet for the cell, and set it to hidden, the separator doesn't completely cover the bottom of the section. I've attached before and after examples. Any help would be appreciated.
The way I've done it with a static table is returned height 0 for the row you want to hide. In my case I made a set of index paths, then implemented it like this:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard hiddenIndexPaths.contains(indexPath as IndexPath) else {
return super.tableView(tableView, heightForRowAt: indexPath)
}
return 0
}
Where hiddenIndexPaths: Set<IndexPath>, is a property on your table view controller that you manage in code. Since it's a static table you should know the index path of the row you want to hide. If you have an outlet already, you can also check that the cell at that index path is the one for your outlet and return height 0 that way. But personally I find the index path set easier.
You also need to make sure that the cell has "clips to bounds" enabled in interface builder.
I think the only way you do it is set the tableview to be Dynamic Prototypes (in IB) .
Every time you try to hide/show a cell, you should callself.tableView.reloadData()
.
Then implement
var hide = false
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if( section == 1 ){
return 3 + ( hide ? 0 : 1 )
}
else {
return 1
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCellWithIdentifier(...) as ...
cell.<textField>.text = ...
return cell
}

Resources