I'm having trouble with insertRowsAtIndexPaths:. I'm not quite sure how it works. I watched the WWDC 2010 video on it, but I'm still getting an error. I thought I was supposed to update the model, then wrap the insertRowsAtIndexPaths: in the tableView beginUpdates and endUpdates calls. What I have is this:
self.customTableArray = (NSMutableArray *)sortedArray;
[_customTableView beginUpdates];
[tempUnsortedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[sortedArray enumerateObjectsUsingBlock:^(id sortedObj, NSUInteger sortedIdx, BOOL *sortedStop) {
if ([obj isEqualToString:sortedObj]) {
NSIndexPath *newRow = [NSIndexPath indexPathForRow:sortedIdx inSection:0];
[_customTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newRow] withRowAnimation:UITableViewRowAnimationAutomatic];
*sortedStop = YES;
}
}];
}];
[_customTableView endUpdates];
customTableArray is my model array. sortedArray is just the sorted version of that array. When I run this code when I hit my plus button to add a new row, I get this error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of rows in section 0. The number of rows contained in an
existing section after the update (2) must be equal to the number of
rows contained in that section before the update (1), plus or minus
the number of rows inserted or deleted from that section (2 inserted,
0 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
I'm not sure what I'm doing wrong. Thoughts? Thanks.
I'd recommend you look a little clearer at what's actually going on in your arrays. As the error reads out, you're telling the table view to add two rows for some reason, while it is saying it "had one row", and then it checks with the data source after the -endUpdates method is called, and the array only has two objects in total, not the three.
In essence, your enumeration is picking up two insertions. Your array has two objects. The table had one object already. 1 existing + 2 insertions = 3 rows. Your array only has two current objects in it. What happened to the extra object.
I would expect that somewhere along the line, either your two arrays are not in sync, or your way of evaluating which is an insert has some form of error.
I hope that helps.
Related
Here i am tryning to add a new row but it's crashing and giving the error "attempt to insert row 3 into section 2, but there are only 3 rows in section 2 after the update". Intially the emerCount is 2 and i am trying to add 3rd row.
var index = NSIndexPath()
if (emerCount<3){
emerCount += 1
index = NSIndexPath(row: emerCount, section: 2)
self.profileTableView?.insertRows(at: [index as IndexPath], with: .automatic)
self.profileTableView?.reloadData()
}
Two issues:
Before calling insertRows you have to insert the item in the data source array into the same location (index emerCount in section 2). This is mandatory.
Basically never call reloadData() right after insertRows. Inserting the row updates the table view with an animation. Remove reloadData().
Further be aware that indexes are zero-based and the third row is indeed inserted at index 2.
PS: Why is the table view optional? Is is created programmatically and displayed temporarily? And don't use NSIndexPath in Swift 3.
More context is needed. What is written in your data source (numberOfRows(inSection:)) methods? It seems that you numberOfRows(inSection:) returns 3 for the section but you want to add one more row.
Delete this line : self.profileTableView?.reloadData()
I have the following code in my search method that updates the tableview.
for (int x = 0; x < [array count]; x++) {
//network stuff here
self.searchedReservations = [aSearchObjectType objectsFromServerDictionaries:aResultsArray];
[self.aTableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
Each object in the array represent a section in my table, for most cases the count will be 4, so 4 sections.
Right now, the code is loading the same data for all sections in the table's cells. Instead of the unique data for each section of the table.
Here is the code that loads the cells. I'm missing some logic that maps the data to the right section of the table.
MyClass *object = [self.searchedReservations objectAtIndex:iIndexPath.row];
cell.textLabel.text = object.customerFullName;
I assume you have the code below in your 'cellForRowAtIndexPath' method:
MyClass *object = [self.searchedReservations objectAtIndex:iIndexPath.row];
cell.textLabel.text = object.customerFullName;
Tables are organised into sections, then within each section there are rows. The rows start at zero again for each section.
If you are on section 0, loading cell 0 this code above is not taking the section number into account, only the row number - so it is loading:
[self.searchedReservations objectAtIndex:0]
to populate the cell.
When you are on section 1, loading cell 0 in section one, you are retrieving exactly the same value because you are just using the row number. ie. you're still loading
[self.searchedReservations objectAtIndex:0]
You may think that you are changing the value of the 'searchedReservations' object between the loading of each section (this is what it looks like you're trying to do in the loop above) but I'm not sure that this is working (as the code the populate searchedReservation doesn't seem to do anything different in each loop counter). Also the first time the table loads it will run through all of the rows in all of the sections anyway.
I think you need to either use the indexPath.section field as well as the indexPath.row field at the time you are populating the cell to ensure you are setting the appropriate row in the appropriate section.
Also use the debugger to see whats going on in your cellForRowAtIndexPath method and in your loop and make sure that you are getting/using a different 'searchedReservations' object for each incrementation of the loop and that this matches the 'searchedReservations' object in the cellForRowAtIndexPath method.
Am confused with the use of this method and the documentation that lists it as a (void) method.
"on return the index path's indexes"
where does it return anything too?
Should it not be:
- (NSIndexPath *)getIndexes:(NSUInteger *)indexes
getIndexes:
Provides a reference to the index path’s indexes.
- (void)getIndexes:(NSUInteger *)indexes
Parameters
indexes
Pointer to an unsigned integer array. On return, the index path’s indexes.
Availability
Available in iOS 2.0 and later.
Declared In
NSIndexPath.h
You have to allocate the NSUInteger array of size [indexPath length] and pass it as argument. The return value will be written there. You have to release that array yourself or do nothing it was created on stack like this:
NSUInteger array[[indexPath length]];
[indexPath getIndexes: array];
Maybe the next sentence explains the reason
It is the developer’s responsibility to allocate the memory for the C array.
It's actually a pointer to a C array that will be filled for you with the indexes, so there's no reason to additionally return it from the function - you already know its address.
You can use the function as follows
NSUInteger indexCount = [indices count];
NSUInteger buffer[indexCount];
[indices getIndexes:buffer maxCount:indexCount inIndexRange:nil];
You send that message to an instance of NSIndexPath, so getting one back wouldn't help. The -getIndexes: method fills the array 'indexes' with the indexes from the index path. So you'd do something like:
NSUInteger *indexes = calloc([indexPath length], sizeof(NSUInteger));
[indexPath getIndexes:indexes];
After that, indexes will be filled with the index values that are in indexPath.
Max, Thomas and Caleb, I have tried all three ways and cannot get anything to work, so maybe fired off the accepted solution too quick.....but probably more likely I just don't get it? I can't get the right size of the array in order to loop through it to access the required rows in my table. I would have though that calloc([indexPath length], sizeof(NSUInteger)) would for a group with 5 rows return an array with 5 rows with each row holding NSUIntegr.....or am of so far off beam it embarrassing?
I have a array (resultArray) which has 21 items of data in it. I want to display it in a 8 sectioned table with different row counts.
How to assign the value properly in all row? Both indexpath.row and section.row gives wrong values. How to assign a single array value to grouped table with more section?
It's up to you to map your data model to the table view, and you can do it any way that you want. If you have a flat array of items and want to map them into different sections of the table view, you'll have to know which offsets of the result data go into which sections of the table, but no one can do that for you automatically, because only you know the semantics of the data. You need some code that takes the section and row index and figures out which index into the results array needs to be returned.
If it's always 21 items and always the same mapping, then hardcoding the mapping in a table or a big bunch of if statements is probably fine. If it's dynamic then you'd need some other lookaside mapping table, depending on how you wanted to map.
Finally, as #iPortable suggests, you could also find a way to structure your results data appropriately, which makes the controller logic simple, depending on your data.
I would create a multi layer array for this. The first level would be the section count and the second level the row. The array would look something like this:
resultArray{
1 = {
1 = first row in first section,
2 = second row in first section
},
2 = {
1 = first row in second section,
2 = second row in second section
}
}
then you get the value from the array in your cellForRowAtIndexPath: as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *sectionArray = [returnArray objectAtIndex:indexPath.section];
cell = [sectionArray objectAtIndex:indexPath.row];
}
i need to hv an array of 20 objects.
initially array will hv 0 objects.
i hv add objbects 1 by 1,till it gets filled with 20 objects.
As soon as array gets 20 objects,and i try to insert a new object(for ex 21st object)
it should delete the 20th object and add itself to first position.
i hope i m giving u a clear picture,about wat i am looking for.
hope for a quick reply
regards
shishir
You could create your own class that uses an NSMutableArray for storage. When adding an item, first check whether there are already 20 objects in the array. If there are, remove the last object from the array. Then add the new object at the front.
- (void)addObject:(id)anObject
{
if ([dataArray count] == 20) {
[dataArray removeLastObject];
}
[dataArray insertObject:anObject atIndex:0];
}
The above will always add the newest object at the front of the array. I guess that is what you want.