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
Related
I call tableView.reloadData() inside of didSet{} of the items variable.
I got a crash in the cellForRowAt function only once, never before, never after with no code changes.
override func tableView(_ tableView: UITableView, number ofRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.tag = indexPath.row
let item = items[indexPath.row] //Thread 1: Fatal error: Index out of range
cell.textLabel?.text = item.title
The possible solution will be you need to handle to solve the crash.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row > items.count-1){
return UITableViewCell()
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.tag = indexPath.row
let item = items[indexPath.row] //Thread 1: Fatal error: Index out of range
cell.textLabel?.text = item.title
return cell
}
}
Maybe this will help.
I can see it happening if the table is scrolling quickly and you update the data source: it could hit a race condition where it tries to call cellForRowAt one more time before it realizes you changed the data source. As a precaution, I'd suggest always adding a check that your index is less than the array's count. Maybe it's paranoid, but better than a crash.
e.g:
Array has 100 items.
Swipe hard sending you towards bottom of table.
While scrolling, the array is updated to only have 10 items.
Table scroll asks for cell at row 99 because it didn't get the message yet.
Crash when you ask for item 99 in an array with only 10 items.
This crash appears when your index is more than array's count.
This crash may appear when scrolling the table view and table view get's updated. You are trying to fetch the index more than array count.
You can check the condition of indexpath.row less than array count.
Try using some thing like this
var fileNameArray = [Audio](){
didSet{
if fileNameArray.count > 0{
recordingListTableView.reloadData()
}
}
}
Is It required to do this ?
crash Is index out of range
Are you Re-Updating Array After this didSet Statement ? if Yes, Do not use this DidSet case here , use if Array is not going to be updated again ,
If you still want to use , Also make use of WillSet Case After didSet()
override func tableView(_ tableView: UITableView, number ofRowsInSection section: Int) -> Int {
guard let items.count > 0 else {return 0}
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.tag = indexPath.row
let item = items[indexPath.row]
cell.textLabel?.text = item.title
}
I think items array does not have any value so it does crash. So, try this above code.
My Situation: I want to save Data from an Array at Index X in an Row on Index X in Section 1.
My code is:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return setObjectToPass.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellEmpty = tableView.dequeueReusableCellWithIdentifier("LabelCell")
var countCell = 0
while countCell < setObjectToPass.count {
let indexPaths = NSIndexPath(forRow: countCell, inSection: 0)
let cell = tableView.dequeueReusableCellWithIdentifier( "LabelCell", forIndexPath: indexPaths)
cell.textLabel!.text = String(setObjectToPass[countCell])
print(cell)
countCell+=1
return cell
}
My Problem is that only the first index of the Array SetObjectToPass is passed and set into the Cell.text
while counter < fetchResult?.count {
let set = fetchResult![counter]
counter+=1;
setObject.append((set.reps?.integerValue)!)
}
You are implementing the tableView(_:cellForRowAtIndexPath:indexPath:) method wrongly.
Remember, every delegate method in UITableViewDelegate is like asking you a question. For example, numberOfSectionsInTableView(_:) is like asking you "How many sections do you want in your table view?". You answer the question by returning a value.
tableView(_:cellForRowAtIndexPath:indexPath:) is similar. It asks a question as well. It asks "What should I display in the table row at this index path?"
In your code, it seems like you want to give multiple answers - looping through the array and attempting to return multiple times. But it doesn't work that way, you can only give one answer.
In the first iteration of the while loop, the execution hits return and stopped. That's why you only see the first table cell.
Thus, you should change your code so that it only gives one answer to the question:
let cell = tableView.dequeueReusableCellWithIdentifier("LabalCell")
cell.textLabel?.text = String(setObjectsToPass[indexPath.row])
return cell
Don't use the loop in cellForRowAtIndexPath delegate method. cellForRowAtIndexPath method call each row based upon numberOfRowsInSection count rows, simply use indexpath.row, Use this code,
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cellEmpty = tableView.dequeueReusableCellWithIdentifier("LabelCell")
let cell = tableView.dequeueReusableCellWithIdentifier( "LabelCell", forIndexPath: indexPaths)
cell.textLabel!.text = setObjectToPass[indexPath.row] as? String
return cell
}
hope its helpful
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.
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.
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
}