NSInternalInconsistencyException when removing rows from a UITableView - ios

I'm receiving an error indicating that I need to update the number of rows in my UITableView after I have deleted a row. I realise that It's because I've not updated the amount of rows in the UITableView, I'm just not sure how to make this change in the code I have below.
Any assistance is really appreciated.
!-- code
NSIndexPath[] rowsToReload = new NSIndexPath[] {
NSIndexPath.FromRowSection(1, 1)
};
dv.TableView.BeginUpdates ();
dv.TableView.DeleteRows(rowsToReload,UITableViewRowAnimation.Automatic);
dv.TableView.EndUpdates ();
!-- error
Name: NSInternalInconsistencyException Reason: Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (3) must be equal to the number of rows contained in that section before the update (3)

Your code above is OK. However, you need to call it after you have removed the corresponding items from your data source.
For example, if you are filling your table view from a List<string> (myList) and you wanted to remove the first row:
myList.RemoveAt(0); // remove the item from the list first
NSIndexPath[] rowsToDelete = new NSIndexPath[] {
NSIndexPath.FromRowSection(0, 0)
};
dv.TableView.DeleteRows(rowsToDelete, UITableViewRowAnimation.Automatic);
No need to wrap the DeleteRows call in a Begin/EndUpdates, as you only have one delete action to perform. That is used when you have multiple different actions (eg. DeleteRows + InsertRows) so that the animations are performed smoothly.

#Dimitris thanks for answering my question. I ended up solving the problem by:
calling the reload method on my UITableView
NSIndexPath[] rowsToReload = new NSIndexPath[] {
NSIndexPath.FromRowSection(1, 1)
};
dv.TableView.ReloadRows (rowsToReload,UITableViewRowAnimation.None);
in my UITableViewCell GetCell method
I removed the label, field and button that were included on the first load of the table. Since this screen in my app will be seen only once, when the user loads it for the first time.

Related

NSInternalInconsistencyException occurs when insertng indexPath into tableView but only when row count gets above a certain threshold

I have two tables in which I am dragging and dropping between them: sourceTableView and targetTableView. They each have their own tableViewController. A parentContainerViewController manages a 'slide out' UI which allows the user to 'longPressGesture' on the sourceTableView cell which causes sourceTableView to slide out exposing the targetTableView below at which time the user can 'drop' the dragged cell into place within the targetTableView. All works well as it should until the targetTableView grows to about 21-27 rows in size. Once we get to this size and if I re-run the project I start to get the NSInternalInconsistencyException. The detail of the error reads: reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (27) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
At first I thought I was getting a race condition issue since the number of rows before the update is "0" and after it is "27". Maybe the tableView wasn't able to load before the user drags in the item and calls the insertIndex method on tableView. But then I noticed that it works fine until we get to a certain length. Race condition wouldn't make sense in this case. Now I am thinking it has something to do with with 'visible cell' loaded vs not loaded. But why would it be '0' rows? I have looked all over for the answer. There are many NSInconsistency but none that seem to answer my specific problem.
This is the function call to tell targetTableViewController to insert an item into its datasource then tells targetTableView to insertRowsAtIndexPath :
dragDropDataSource.tableView(self, insertDataItem: item, atIndexPath: indexPath)
self.beginUpdates()
self.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
self.endUpdates()
Here is the targetTableViewController code implementing the above call:
func tableView(tableView: UITableView, insertDataItem dataItem : AnyObject, atIndexPath indexPath: NSIndexPath) -> Void {
if let di = dataItem as? DataItem {
data.insert(di, atIndex: indexPath.row)
}
data is the array that stores the 'DataItems' which are shown in the tableView rows.
Additionally. The targetTableView is initialized with data via a call in its viewDidLoad() to getMyTopTen()
func getMyTopTen() {
let pwAPI = PowWowAPI()
pwAPI.getMyTopTen(self.boardId!) {
(entries:[Entry])in
for(var i=0; i < entries.count; i++) {
let dataItem = DataItem(indexes: String(i), entry: entries[i])
self.data.append(dataItem)
}
}
dispatch_async(dispatch_get_main_queue()) {
self.targetTableView.reloadData()
}
}
I hope I have explained the problem sufficiently. If not please help me make this question better. I am new to asking questions here.

How to detect when UITableView has finished loading all the rows? [duplicate]

This question already has answers here:
How to detect the end of loading of UITableView
(22 answers)
Closed 6 years ago.
I need to call a function after the UITableView has been loaded completely. I know that in most cases not every row is displayed when you load the view for the first time, but in my case, it does as I only have 8 rows in total.
The annoying part is that the called function needs to access some of the tableView data, therefore, I cannot call it before the table has been loaded completely otherwise I'll get a bunch of errors.
Calling my function in the viewDidAppear hurts the user Experience as this function changes the UI. Putting it in the viewWillAppear screws up the execution (and I have no idea why) and putting it in the viewDidLayoutSubviews works really well but as it's getting called every time the layout changes I'm afraid of some bugs that could occur while it reloads the tableView.
I've found very little help about this topic. Tried few things I found here but it didn't work unfortunately as it seems a little bit outdated. The possible duplicate post's solution doesn't work and I tried it before posting here.
Any help is appreciated! Thanks.
Edit: I'm populating my tableView with some data and I have no problems with that. I got 2 sections and in each 4 rows. By default the user only sees 5 rows (4 in the first section, and only one in the second the rest is hidden). When the user clicks on the first row of the first section it displays the first row of the second section. When he clicks on the second row of the first section it displays two rows of the second section, and so on. If the user then clicks on the first row of the first section again, only one cell in the second section is displayed. He can then save his choice.
At the same time, the system changes the color of the selected row in the first section so the users know what to do.
Part of my issue here is that I want to update the Model in my database. If the users want to modify the record then I need to associate the value stored in my database with the ViewController. So for example, if he picked up the option 2 back then, I need to make sure the second row in the first section has a different color, and that two rows in the second sections are displayed when he tries to access the view.
Here's some code :
func setNonSelectedCellColor(indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath)
currentCell?.textLabel?.textColor = UIColor.tintColor()
for var nbr = 0; nbr <= 3; nbr++ {
let aCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: nbr, inSection: 0))
let aCellIndexPath = tableView.indexPathForCell(aCell!)
if aCellIndexPath?.row != indexPath.row {
aCell?.textLabel?.textColor = UIColor.blackColor()
}
}
}
func hideAndDisplayPriseCell(numberToDisplay: Int, hideStartIndex: Int) {
for var x = 1; x < numberToDisplay; x++ {
let priseCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: x, inSection: 1))
priseCell?.hidden = false
}
if hideStartIndex != 0 {
for var y = hideStartIndex; y <= 3; y++ {
let yCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: y, inSection: 1))
yCell?.hidden = true
}
}
}
These two functions are getting called every time the user touches a row :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let path = (indexPath.section, indexPath.row)
switch path {
case(0,0):
setNonSelectedCellColor(indexPath)
hideAndDisplayPriseCell(1, hideStartIndex: 1)
data["frequencyType"] = Medecine.Frequency.OneTime.rawValue
case(0,1):
setNonSelectedCellColor(indexPath)
hideAndDisplayPriseCell(2, hideStartIndex: 2)
data["frequencyType"] = Medecine.Frequency.TwoTime.rawValue
case(0,2):
setNonSelectedCellColor(indexPath)
hideAndDisplayPriseCell(3, hideStartIndex: 3)
data["frequencyType"] = Medecine.Frequency.ThreeTime.rawValue
case(0,3):
setNonSelectedCellColor(indexPath)
hideAndDisplayPriseCell(4, hideStartIndex: 0)
data["frequencyType"] = Medecine.Frequency.FourTime.rawValue
default:break
}
}
I store the values in a dictionary so I can tackle validation when he saves.
I'd like the first two functions to be called right after my tableView has finished loading. For example, I can't ask the data source to show/hide 1 or more rows when I initialize the first row because those are not created yet.
As I said this works almost as intended if those functions are called in the viewDidAppear because it doesn't select the row immediately nor does it show the appropriate number of rows in the second sections as soon as possible. I have to wait for 1-2s before it does.
If you have the data already that is used to populate the tableView then can't you use that data itself in the function? I am presuming that the data is in the form of an array of objects which you are displaying in the table view. So you already have access to that data and could use it in the function.
But if that's not the case then and if your table view has only 8 rows then you can try implementing this function and inside that check the indexPath.row == 7 (8th row which is the last one).
tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
Since all your rows are visible in one screen itself without scrolling you could use this function to determine that all the cells have been loaded and then call your function.

CollectionView.DeleteItems throws exception NSInternalInconsistencyException

I'm getting this exception when I try to call DeleteItems on my UICollectionView. I've googled around and most people are saying they solve this by NOT calling ReloadData on the CollectionView after they call DeleteItems, but I know I'm not calling that. I even overrode it and put a break point on ReloadData and confirmed that it's not getting called.
this.InvokeOnMainThread(() =>
{
CollectionView.DeleteItems (new NSIndexPath [] { indexPath });
});
Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (5) must be equal to the number of items contained in that section before the update (5), plus or minus the number of items inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).
Looks like I needed to update my list that was tied to my datasource BEFORE calling DeleteItems:
this.InvokeOnMainThread(() =>
{
this.MyList.RemoveAt(indexPath.Row);
CollectionView.DeleteItems (new NSIndexPath [] { indexPath });
});

MonoTouch, UITableViewController, How to insert a row in a section?

I designed a UITableViewController with static cells in XCode.
After click on a button I want to add a row in one of the sections with a result.
My code:
InvokeOnMainThread (() => {
List<NSIndexPath> indexPaths = new List<NSIndexPath>();
indexPaths.Add(NSIndexPath.FromRowSection(0, 2));
TableView.InsertRows(indexPaths.ToArray(), UITableViewRowAnimation.Fade);
});
didn't work :-)
I get this error message: * Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2380.17/UITableView.m:1070
Do you add data to your data source (IE a new row or section) after you insert the rows. You need to because inserting automatically does a myTable.reloadData, resulting in all the datasource methods being called again. If you explicitly told it to add a row at a specific index and it goes to reload and finds that index doesn't exists you get errors like this. Check cellForRow and numCellInSection

Showing/Hiding Rows in Sections of UITableView

I am trying to create a UITableView that is set up so that when I click on a section, it hides the rows from the previous section and shows the rows of the newly selected section. The tableView is set up with data from an array of arrays called menuItems. menuItems contains several other arrays including contactInfoArray, clientInfoArray, jacketArray, and shirtArray. In each of these arrays, the objectAtIndex:0 is the Section Title and effectively acts as the header.
So, for example when the app loads, it should first show all rows of the contactInfoArray, but then show the ObjectAtIndex:0 (the title) for each of the other arrays. When I then tap one of those section titles, for example: "Jacket", I need the table to hide the contactInfoArray objectsAtIndexes:1+, but not object 0, while at the same time (or with an acceptable delay) showing jacketArray objectsAtIndexes:1+.
I have achieved the desired result by calling reload data, but I want animation of the change and reloadData does not allow that. I can't find any tutorials or sample code that does this.
Can anybody help me?
Thanks to my good friend Darren for helping me solve this issue!
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section{
return (indexPath.section == currentSection) ? [[menuItems objectAtIndex: indexPath.section ] count] : 1;
}
All that I needed to do was set an immediate variable (in my case "currentSection" which is an int) and set its value in the didSelectRowAtIndexPath: method. Then I set up my table so that row 0 of the section acted as the section title.
Doing this made it so that when I clicked on the section header it would "collapse" the open section and "expand" the newly selected section.

Resources