Invalid update: invalid number of rows in section - ios

I am working on a project using Microsoft Azure services. In that while deleting a row I am getting 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 (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
Code for table load and delete row is as :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//medicine list
if (section == 0) {
NSArray *sectionInfo = [self.fetchedResultsController1 fetchedObjects];
return [sectionInfo count];
}
//allergy list
else if (section == 1) {
NSArray *sectionInfo = [self.fetchedResultsController2 fetchedObjects];
return [sectionInfo count];
}
//notes list
else if (section == 2){
NSArray *sectionInfo = [self.fetchedResultsController3 fetchedObjects];
return [sectionInfo count];
}
else
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"mcell";
MedicationTableViewCell *cell = (MedicationTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Add utility buttons
NSMutableArray *rightUtilityButtons = [NSMutableArray new];
[rightUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:0.231f blue:0.188 alpha:1.0f] title:#"Delete"];
switch (indexPath.section) {
case 0: {
NSManagedObject *item = [self.fetchedResultsController1 objectAtIndexPath:indexPath];
cell.textLabel.text = [item valueForKey:#"name"];
break;
}
case 1: {
NSManagedObject *item = [self.fetchedResultsController2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
cell.textLabel.text = [item valueForKey:#"name"];
break;
}
case 2: {
NSManagedObject *item = [self.fetchedResultsController3 objectAtIndexPath: [NSIndexPath indexPathForRow:indexPath.row inSection:0]];
cell.textLabel.text = [item valueForKey:#"title"];
break;
}
default:
break;
}
cell.rightUtilityButtons = rightUtilityButtons;
cell.delegate = self;
return cell;
}
- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index {
// Delete button is pressed
NSIndexPath *cellIndexPath = [self.medicationsTableView indexPathForCell:cell];
//fetchingg data from local store first
NSManagedObject *item = [self.fetchedResultsController1 objectAtIndexPath:[NSIndexPath indexPathForRow:cellIndexPath.row inSection:0]];
NSMutableArray *keys = [[NSMutableArray alloc] initWithObjects:#"id", #"name", #"userId", nil];
NSMutableArray *values = [[NSMutableArray alloc] initWithObjects: [item valueForKey:#"id"], [item valueForKey:#"name"], [item valueForKey:#"userId"], nil];
//creating dictionary of data
NSDictionary *dict = [[NSDictionary alloc] initWithObjects:values forKeys:keys];
//calling delete fucntion
[self.authService deleteItem:self.syncTable withDict:dict completion:^{
//removing row from table view
[self.medicationsTableView reloadData];
[self.medicationsTableView deleteRowsAtIndexPaths:#[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
}];
break;
}
Please tell where I am going wrong. Thanks in advcance!!!!

In - (void)swipeableTableViewCell: didTriggerRightUtilityButtonWithIndex:
You need to remove either
[self.medicationsTableView reloadData];
or
[self.medicationsTableView deleteRowsAtIndexPaths:#[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
Because on first line when reloadData get called it's reload the tableview with new datasource and again calling deleteRowsAtIndexPaths tried to delete a rows which already removed by calling reloadData earlier.

The important thing is that you need to use either
[self.medicationsTableView reloadData];
or
[self.medicationsTableView deleteRowsAtIndexPaths:#[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
The reason being, when the tableview's reload data is called the row which is removed from data source is deleted and after that when the delete row api is called for the same index path(where the row is already deleted causes the issue)
Also just before deleting the row from the table delete the object from the data source (self.fetchedResultsController1) and call
[self.medicationsTableView deleteRowsAtIndexPaths:#[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
and after the above row's deletion animation is completed than you can call(but it is not required)
[self.medicationsTableView reloadData];

Related

iOS UItableView remove object from array by index path

I have custom contact book sorted by A-Z sections. I am trying to add to an array selected contacts
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *contactInfo = [NSMutableDictionary new];
Cell *cell = (Cell *)[self.contTableView cellForRowAtIndexPath:indexPath];
//NSLog(#"CELL %#", cell.contact.fullname);
if (!cell.contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
cell.contact.contactChecked = YES;
//NSLog(#"DID SELECT %#", cell.contact.fullname);
NSLog(#"index checked row %d section %d", indexPath.row, indexPath.section);
[contactInfo setValue:cell.contact.fullname forKey:#"name"];
[contactInfo setValue:cell.contact.numbers.firstObject forKey:#"phone"];
[self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];
} else {
NSLog(#"index unchecked row %d section %d", indexPath.row, indexPath.section);
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
cell.contact.contactChecked = NO;
[self.seletedPeople removeObjectAtIndex:indexPath.row];
}
NSLog(#"DICT SELECTED %#", self.seletedPeople);
}
What happens, that in some cell app crashing with error
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM insertObject:atIndex:]: index 1 beyond
bounds for empty array'
*** First throw call stack: (0x29c02fef 0x38150c8b 0x29b1cf8f 0xf7fe9 0x2d36e56b 0x2d41d43b 0x2d2d2a91 0x2d24d38f 0x29bc8fed 0x29bc66ab
0x29bc6ab3 0x29b13201 0x29b13013 0x313f2201 0x2d2b7a59 0x10c075
0x386dcaaf) libc++abi.dylib: terminating with uncaught exception of
type NSException
UPDATE:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"Cell";
Cell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (searchResults) {
//NSLog(#"CELL %#", cell.contact.fullname);
contact = [searchResults objectAtIndex:indexPath.row];
cell.contact = contact;
cell.firstNameLabel.text = contact.fullname;
cell.avatar.image = contact.image;
cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
cell.avatar.layer.borderWidth = 0.5;
cell.avatar.layer.cornerRadius = 25.0;
cell.avatar.layer.masksToBounds = YES;
cell.number.text = contact.numbers.firstObject;
} else {
NSString *sectionTitle = [[[namesDictionary allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]
objectAtIndex:indexPath.section];
NSArray *sectionContacts = [namesDictionary objectForKey:sectionTitle];
contact = [self getContactFromArray:[sectionContacts objectAtIndex:indexPath.row]];
cell.firstNameLabel.text = [sectionContacts objectAtIndex:indexPath.row];
cell.avatar.image = contact.image;
cell.avatar.layer.borderColor = [UIColor grayColor].CGColor;
cell.avatar.layer.borderWidth = 0.5;
cell.avatar.layer.cornerRadius = 25.0;
cell.avatar.layer.masksToBounds = YES;
cell.number.text = contact.numbers.firstObject;
cell.contact = contact;
cell.tag = indexPath.row;
}
if (contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
} else {
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
}
return cell;
}
The way I use in such cases. I create a model class and load the tableview with models. Now when i select a cell or deselect a cell. I just add that model in another array. After that when i de select the already selected cell, i can get the same model from the indexpath.row and then i can use NSArray method to fetch that model in that selected array and remove it from there. To fix your issue you can use indexPath.row as another key in dictionary during selection. After that when you deselect the cell use a predicate to get the added dictionary from the array that you are using to store selected ones. Once you find it delete it from the array.
the problem here is the coupling of model with view objects , you shouldn't inquire about a certain property from the view itself (in your case the Cell) however the contact checked should have a reflect on its model from the data source object (the one you used to feed the cellForRowAtIndexPath: , where it should be inquired from.
Otherwise the code is buggy and unstable due to that coupling since it might point to an empty object
The problem is here:
[self.seletedPeople insertObject:contactInfo atIndex:indexPath.row];
if selectedPeople is empty and the user clicks on row 2, then it's going to try to insert contactInfo into row 2 which is "beyond the bounds of an empty array". Simply use addObject: instead. You'll also need to change how you remove items from that array then (probably better to use a dictionary instead).
The solution was adding contact record id to my dictionary and search with predicate this contact id. then remove it. kudos to #jassi
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *contactInfo = [NSMutableDictionary new];
Cell *cell = (Cell *)[tableView cellForRowAtIndexPath:indexPath];
if (!cell.contact.contactChecked) {
cell.contactImage.image = [UIImage imageNamed:#"cell_blue_circle.png"];
cell.contact.contactChecked = YES;
//NSLog(#"DID SELECT %#", cell.contact.fullname);
NSLog(#"index checked %# ", [indexPath description]);
[contactInfo setValue:cell.contact.fullname forKey:#"name"];
[contactInfo setValue:cell.contact.numbers.firstObject forKey:#"phone"];
[contactInfo setValue:#(cell.contact.contactId) forKey:#"contactId"];
[self.seletedPeople addObject:contactInfo];
} else {
NSLog(#"index unchecked %#", [indexPath description]);
cell.contactImage.image = [UIImage imageNamed:#"cell_gray_circle.png"];
cell.contact.contactChecked = NO;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"contactId == %d", cell.contact.contactId];
NSArray *resultTemp = [self.seletedPeople filteredArrayUsingPredicate:predicate];
if(resultTemp.count>0)
[self.seletedPeople removeObject:resultTemp[0]];
}
NSLog(#"DICT SELECTED %#", self.seletedPeople);
}
As user2320861 said, the problem is on the line where you use insertObject. I would do the following:
Change self.selectedPeople to a NSMutableDictionary using the following code:
//in your #interface
#property (nonatomic, strong) NSMutableDictionary *selectedPeople;
Change the code in didSelectCellAtIndexPath to:
//Since phone numbers are unique.
self.selectedPeople[cell.contact.numbers.firstObject] = contactInfo;
Retrieve all of the contacts later using this code:
for(id key in self.selectedPeople) {
NSDictionary contactInfo = [self.selectedPeople objectForKey:key];
//Do something with that contactInfo
}

Assertion failure in UITableView _endCellAnimationsWithContext [duplicate]

This question already has answers here:
'Invalid update: invalid number of rows in section 0
(4 answers)
Closed 8 years ago.
i have a problem like this :
i am loading some data to a table view after select a date from a date picker.the data which i want to load is loaded to a variable inside the didSelectRowAtIndexPath method. when the table is checking for the number of rows it checks the count of that variable is grater than zero and so on..
my problem is this : when i load the data to the variable by calling a web service [using AFNetworking library] it is works nicely. but when i get the data directly [i have implemented a method to call web service before the table load, and holds the data] by a method it is giving this error
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:1330
2014-05-02 17:25:12.665 varrdle_v2[1428:a0b] * 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 (3) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
* First throw call stack:
i cant figure out why that happens. the only different is the way i taken the data.
below is my implementation
number of rows
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray* reqFdate= [TableViewController getrequestPerDate];
NSLog(#"Count OF REQUESTS: %d",reqFdate.count);
if (reqFdate.count == 0 ) {
NSInteger numberOfRows = [self.persons count];
if ([self datePickerIsShown]){
numberOfRows++;
}
NSLog(#"NO OF ROWS in IF %d",numberOfRows);
return numberOfRows;
}
else{
NSLog(#"NO OF ROWS %d",reqFdate.count);
return reqFdate.count;
}
}
cell for row at indexpath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// display in 12HR/24HR (i.e. 11:25PM or 23:25) format according to User Settings
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSString *currentTime = [dateFormatter stringFromDate:today];
NSDate *date=[dateFormatter dateFromString:currentTime];
if(indexPath.row==0){
VCPerson *person = self.persons[0];
cell = [self createPersonCell:person];
}
else if ([self datePickerIsShown] && (self.datePickerIndexPath.row == 1)){
// VCPerson *person = self.persons[indexPath.row -1];
cell = [self createPickerCell:date];
}
else{
TacleCell *cell = (TacleCell*)[self.tableView dequeueReusableCellWithIdentifier:otherCellID];
cell.delegate = self;
if(cell == nil)
{
cell = [[TacleCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:otherCellID];
}
else
{
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:cell.profileImage];
}
return cell;
}
return cell;
}
didSelect method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView beginUpdates];
int countOfRowss = [TableViewController getrequestPerDate].count;
if(countOfRowss>0)
{
NSArray* indexpathsArry = [self getIndexPaths];
[self.tableView deleteRowsAtIndexPaths:indexpathsArry withRowAnimation:YES];
requestForDate = nil;
}
if ([self datePickerIsShown] && (self.datePickerIndexPath.row - 1 == indexPath.row)){
[self hideExistingPicker];
//[self.tableView reloadData];
//[self viewDidLoad];
//call the service and take the results
NSString* selecteDate = [TableViewController getDate];
//NSString* prsonID =[LoginView getPersonID];
// here i call this method and get the data.
requestForDate= [self filterRequestForDate:selecteDate];
NSLog(#"FILTERED REQUESTS :%#",requestForDate);
//requestForDate = nil;
[self.tableView reloadData];
// NSString* selecteDate = [ScheduleView getDate];
// this is how i fetch the data by using a web service
/* NSString* prsonID =[LoginView getPersonID];
NSDictionary* parms = [NSDictionary dictionaryWithObjectsAndKeys:prsonID,#"caregiverPersonId",selecteDate,#"selectedDate", nil];
jsonpaser* jp = [[jsonpaser alloc]init];
//[self.indicator_process startAnimating];
[jp getWebServiceResponce:#"myUrl" :parms success:^(NSDictionary *responseObject)
{
requestForDate = responseObject;
NSLog(#"RESPONSEFORDATE_IN DIDSELECT :%#",requestForDate);
NSArray* indexpaths = [self getIndexPaths];
NSLog(#"indexPATHS %#",indexpaths);
//[self.indicator_process stopAnimating];
//[_dimmingView removeFromSuperview];
[self.tableView reloadData];
}];
*/
}
else{
//--
NSIndexPath *newPickerIndexPath = [self calculateIndexPathForNewPicker:indexPath];
if ([self datePickerIsShown]){
[self hideExistingPicker];
}
[self showNewPickerAtIndex:newPickerIndexPath];
self.datePickerIndexPath = [NSIndexPath indexPathForRow:newPickerIndexPath.row + 1 inSection:0];
NSLog(#"DATEPICKERINDEX %#",self.datePickerIndexPath);
//self.datePickerIndexPath = nil;
}
// this is the line where a row deleted
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self.tableView endUpdates];
}
please someone tell me where is the issue...
thank you
Regarding to apple documentation apple link you should not call reloadData between beginUpdates and endUpdates.
You should remove the beginUpdates and endUpdates or move the reloadData outside the group.

Delete selected images from a row containing multiple cells in UITableView

I have a UITableView containing list of images, each row contains 4 UITableViewCell,
the user can select multiple images (selection is by hiding and showing an overlay image on the cell)
what i want to do is when user click delete button is to remove the selected image from my table.
Here is some of the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
ThumbnailImageCell *cell = (ThumbnailImageCell *)[tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil)
{
cell = [[[ThumbnailImageCell alloc] initWithManagedImages:[self imagesForIndexPath:indexPath] reuseIdentifier:CellIdentifier] autorelease];
}
else
{
[cell setImages:[self imagesForIndexPath:indexPath]];
}
return cell;}
-(NSArray*)imagesForIndexPath:(NSIndexPath*)_indexPath {
int index = (_indexPath.row*4);
int maxIndex = (_indexPath.row*4+3);
if(maxIndex < [self.imagesArray count]) {
return [NSArray arrayWithObjects:[self.imagesArray objectAtIndex:index],
[self.imagesArray objectAtIndex:index+1],
[self.imagesArray objectAtIndex:index+2],
[self.imagesArray objectAtIndex:index+3],
nil];
}
else if(maxIndex-1 < [self.imagesArray count]) {
return [NSArray arrayWithObjects:[self.imagesArray objectAtIndex:index],
[self.imagesArray objectAtIndex:index+1],
[self.imagesArray objectAtIndex:index+2],
nil];
}
else if(maxIndex-2 < [self.imagesArray count]) {
return [NSArray arrayWithObjects:[self.imagesArray objectAtIndex:index],
[self.imagesArray objectAtIndex:index+1],
nil];
}
else if(maxIndex-3 < [self.imagesArray count]) {
return [NSArray arrayWithObject:[self.imagesArray objectAtIndex:index]];
}
return nil;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return ceil([self.imagesArray count] / 4.0);
}
What I tried to do is the following but without any success till now
-(void)finishDeleting{
int countOfDeletedThread;
[self setEditing:YES animated:YES];
[self.tableView beginUpdates];
NSMutableIndexSet *mutableIndexSet = [[NSMutableIndexSet alloc] init];
NSMutableArray *indexToDelete = [[NSMutableArray alloc] init];
NSIndexPath *indexPath ;
for(ThumbnailImage *thumbnailImage in self.imagesArray)
{
if([thumbnailImage selected])
{
countOfDeletedThread = countOfDeletedThread+1;
indexPath = [NSIndexPath indexPathForRow:countOfDeletedThread inSection:0];
[indexToDelete addObject:indexPath];
[mutableIndexSet addIndex:indexPath.row];
}
}
[self.imagesArray removeObjectsAtIndexes:mutableIndexSet];
[self.tableView deleteRowsAtIndexPaths:indexToDelete withRowAnimation:UITableViewRowAnimationFade];
[indexToDelete release];
[mutableIndexSet release];
[self.tableView endUpdates];
[self.tableView setEditing:NO animated:YES];
[self.tableView reloadData];
[CATransaction flush];}
Any help please? I am stuck for 2 days and don't know what to do.
Thank you.
If I understand it correctly, you have 4 UIImageViews per table row, not
4 UITableViewCells. That means if you delete a subset of the images, the remaining
images will "reflow" across all rows. Therefore it does not make sense to use
beginUpdates/deleteRowsAtIndexPaths/endUpdates. You probably should just
remove the selected images from the data source array self.imagesArray,
call [self.tableView reloadData].
Removing the selected images from the array can be slightly simplified to
NSIndexSet *indexSet = [self.imagesArray indexesOfObjectsPassingTest:^BOOL(ThumbnailImage *thumbnailImage, NSUInteger idx, BOOL *stop) {
return [thumbnailImage selected];
}];
[self.imagesArray removeObjectsAtIndexes:indexSet];
Note that UICollectionView (available since iOS 6) might be better suited to display
multiple images per row.

delete last row in TableView and show a "no results" label in new cell

I have a problem with my UITableView where deleting the last row in the section terminates the app with an NSInternalInconsistencyException:
*** 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 (1) 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 (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
My UITableView is populated with MPMediaItems from an MPMediaItemCollection (self.detailCollection). When the last one gets deleted I want to show a "No results found" label in a blank cell.
Here is my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
if ([[self.detailCollection items] count] == 0) {
[tableView numberOfRowsInSection:1];
cell.textLabel.text = #"No results found";
//return cell;
} else {
MPMediaItem *song = (MPMediaItem *)[[self.detailCollection items] objectAtIndex:[indexPath row]];
if (song) {
cell.textLabel.text = [song valueForProperty:MPMediaItemPropertyTitle];
MPMediaItemArtwork *art = [song valueForProperty:MPMediaItemPropertyArtwork];
cell.imageView.image = [art imageWithSize:CGSizeMake(64, 64)];
}
}
return cell;
}
Here is my code for deleting the rows:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
PlaylistData *pData = [PlaylistData getInstance];
NSMutableArray *tempArray = [[self.eventDictionary valueForKey:[NSString stringWithFormat:#"%#", pData.selectedEvent]] mutableCopy];
NSMutableArray *newArray = [[NSMutableArray alloc] init];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView beginUpdates];
// Delete the row from the data source
[tempArray removeObjectAtIndex:indexPath.row];
[self.eventDictionary setValue:tempArray forKey:[NSString stringWithFormat:#"%#", pData.selectedEvent]];
[[NSUserDefaults standardUserDefaults] setValue:self.eventDictionary forKey:#"Playlist Items"];
[[NSUserDefaults standardUserDefaults] synchronize];
if ([tempArray count] == 0) {
[tableView numberOfRowsInSection:1];
}
for (int i=0; i<[tempArray count]; i++) {
NSString *pID = [NSString stringWithFormat:#"%#", [tempArray objectAtIndex:i]];
unsigned long long ullvalue = strtoull([pID UTF8String], NULL, 0);
NSNumber *UniqueID = [NSNumber numberWithUnsignedLongLong:ullvalue];
MPMediaQuery *cellQuery = [[MPMediaQuery alloc] init];
[cellQuery addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:UniqueID forProperty:MPMediaItemPropertyPersistentID]];
for (MPMediaItem *item in [cellQuery items]) {
[newArray addObject:item];
}
[cellQuery release];
}
if (![newArray count] == 0) {
self.detailCollection = [[MPMediaItemCollection alloc] initWithItems:newArray];
[tableView numberOfRowsInSection:[self.detailCollection count]];
} else {
[tableView numberOfRowsInSection:1];
[tableView reloadData];
}
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
And here is my numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if ([[self.detailCollection items] count] == 0 || [self.detailCollection items] == nil || [self.detailCollection items] == NULL) {
return 1;
}
return [[self.detailCollection items] count];
}
My question is: Why isn't it creating the "No results found" cell when self.detailCollection is == 0?
I think you want something to the effect of:
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
if ([newArray count] == 0) {
[tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[tableView endUpdates];
However, a simpler solution would be to just add a label to your table view. Unless there is some specific reason that you need an actual UITableViewCell to display "No results found".
UILabel *label = [[UILabel alloc] init];
CGRect frame = CGRectMake(0.0, 0.0, 320.0, 44.0);
label.frame = frame;
label.text = #"No results found";
[self.tableView addSubview:label];
One solution that I would recommend is to use a table footer view rather than a new cell. Basically, add a footer to your table that is only visible when the cell count is 0.
You can override the method
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
to get a footer.
When deleting and adding objects, check the new count and then adjust the visibility of the footer from there.
You are calling numberOfRowsInSection in a couple of places. You should never be calling it, it's a call back hook that you implement and the system calls.
The cleanest solution to do this would be to set self.tableView.tableFooterView when rows = 0
#interface UITableView : UIScrollView <NSCoding> {
...
#property(nonatomic,retain) UIView *tableFooterView;
// accessory view below content. default is nil. not to be confused with section footer

Error while deleting a section from my UITableView

I need your help :(
I'm working on a iOS application in which i had to remove some rows and sections in a UItableView.
I'm on Xcode 4.
I associate my tableView with NSarray and dictionary, like this :
NSMutableArray *arrTemp1 = [[NSMutableArray alloc]
initWithObjects:#"Chris",nil];
NSMutableArray *arrTemp2 = [[NSMutableArray alloc]
initWithObjects:#"Bianca",nil];
NSMutableArray *arrTemp3 = [[NSMutableArray alloc]
initWithObjects:#"Candice",#"Clint",#"Chris",nil];
NSMutableArray *arrTemp4 = [[NSMutableArray alloc]
initWithObjects:#"Candice",#"Clint",#"Chris",nil];
NSMutableArray *arrTemp5 = [[NSMutableArray alloc]
initWithObjects:#"Candice",#"Clint",#"Chris",nil];
NSMutableArray *arrTemp6 = [[NSMutableArray alloc]
initWithObjects:#"Candice",#"Clint",#"Chris",nil];
NSMutableDictionary *temp = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:arrTemp1,#"A",arrTemp2,
#"B",arrTemp3,#"C",arrTemp4, #"D", arrTemp5, #"E", arrTemp6, #"J",nil];
self.tableContents = temp;
self.sortedKeys =[[self.tableContents allKeys]
sortedArrayUsingSelector:#selector(compare:)];
When i need to delete a rows or a sectionm i'm using this code ->
(void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSMutableArray *listData = [self.tableContents objectForKey:
[self.sortedKeys objectAtIndex:[indexPath section]]];
NSUInteger row = [indexPath row];
[listData removeObjectAtIndex:row];
[tableView beginUpdates];
if ([listData count] > 0)
{
// Section is not yet empty, so delete only the current row.
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
else
{
// Section is now completely empty, so delete the entire section.
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationFade];
}
[tableView endUpdates];
}
}
When i'm deleting rows, it works well..
When i'm deleting sections, i'm getting the following error :
" * Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-1912.3/UITableView.m:1030
2012-01-13 16:42:45.261 * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (6) must be equal to the number of sections contained in the table view before the update (6), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted).'"
(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [tableContents count]; // tableContent is a NSMUtableDictionnary*
}
- (NSInteger)tableView:(UITableView *)table
numberOfRowsInSection:(NSInteger)section
{
NSArray *listData =[self.tableContents objectForKey:
[self.sortedKeys objectAtIndex:section]];
return [listData count];
}
I'm getting crazy, and coming on stackOverflow to ask for help...
(Sorry for my poor english :( )
Thanks to everyone reading and answering !!
It looks like you're not actually deleting the dictionary key for the empty array when it contains no objects, thus your call to
// Section is now completely empty, so delete the entire section.
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationFade];
is causing the problem as you still have the same number of sections (dictionary keys) as before...
Try swapping these 2 lines around:
[listData removeObjectAtIndex:row];
[tableView beginUpdates];
So it should be:
[tableView beginUpdates];
[listData removeObjectAtIndex:row];

Resources