UITableView insertRowsAtIndexPaths: - iphone

I have a Navigation Controller that contains a uitableview when I press on a row it pops a new view controller on the stack, which is used to display detail information in the detail view it makes a request from the server to get some response information then once the information is returned I use insertRowsAtIndexPaths: to display the information that is returned from the server.
This all works fine the first time, then when i press the back button and select a new row or the same row for viewing the detailed information once I the insertRowsAtIndexPaths: is called i get the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. 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 (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).'
Here is the code for pushing the view on the stack:
VideoDetailViewController_iPhone *nextView = [[VideoDetailViewController_iPhone alloc] initWithNibName:#"VideoDetailViewController_iPhone" bundle:nil withVideo:rowData];
nextView.navController = navController;
[navController pushViewController:nextView animated:YES];
[nextView release];
Here is the code is executed once the information is returned from the server
- (void)fetchVideoDetail:(NSNotification *)notification {
hasLoadedResponses = YES;
NSArray *obj = (NSArray *)[notification object];
responses = [[obj valueForKey:#"responses"] mutableCopy];
//NSLog(#"RESPONSES: %#", responses);
if ([responses count] == 0) {
[tblView reloadData];
return;
}
NSMutableArray *indexes = [[NSMutableArray alloc] init];
int i = 0;
for (NSArray *x in responses) {
if (i > 0) {
//The reason for skipping the first one is because we will change that row once the table refreshes we just need to insert any rows after the first one.
[indexes addObject:[NSIndexPath indexPathForRow:i inSection:1]];
}
i++;
}
//NSLog(#"indexCount: %i", [indexes count]);
[tblView beginUpdates];
[tblView insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationBottom];
[tblView endUpdates];
//[tblView reloadData];
}
Here is the tableView methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (section == 0) {
return 1;
} else {
if ([responses count] == 0) {
NSLog(#"numberofrowsinsection: 1");
return 1;
} else {
NSLog(#"numberofrowsinsection: %i", [responses count]);
return [responses count];
}
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
VideoCell *cell = (VideoCell *)[tableView dequeueReusableCellWithIdentifier:CellClassName];
if (cell == nil) {
NSArray *topLevelItems = [cellLoader instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
}
if (indexPath.section == 0) {
cell.lblTitle.text = [data title];
cell.lblDescription.text = [data videoDescription];
} else {
if ([responses count] == 0) {
if (!hasLoadedResponses) {
cell.lblTitle.text = #"";
cell.lblDescription.text = #"";
} else {
//Responses have been loaded
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.lblTitle.text = #"No responses to this video";
cell.lblDescription.text = #"Be the first to respond by selecting the \"Set as Destination\" button above";
}
} else {
//Display the response information
cell.lblTitle.text = [[responses objectAtIndex:indexPath.row] valueForKey:#"title"];
cell.lblDescription.text = [[responses objectAtIndex:indexPath.row] valueForKey:#"description"];
}
}
return cell;
}

Your datasource and number of rows are out of sync. When you insert the row, you have to increase the number of rows in the section at the same time. In this case you would have to increase the count of your array responses, which you are using in your numberOfRowsInSection method.

Related

how to populate more tableview sections with one array

I'm working on a tableview that displays data about a company. I want to divide the data over 3 sections, to make it look more organized.
The data about a company is retreived from a mysql database and I receive it in one array, which looks like this:
{
companyAdress = "the street 9";
companyCity = "city";
companyFacebook = "facebook.com/companyname";
companyName = "name";
companyPhoneNumber = "0123 456 789";
companyTwitter = "www.twitter.com/companyname";
companyWebsite = "www.companyname.com";
companyZip = "0000 AA";
imageNumber = "3067913";
}
I want the companyName and imageNumber in the first section, the companyAdress, companyZip and companyCity in the second, and all the remaining variables in the third section.
I do not know how to properly do this, and I haven't found a useful answer/solution for this on SO or any other website I know.
How to I do this? any help, sample code and/or tutorial would be much appreciated, thank you in advance!
One approach would be to separate the data when you receive it into a two-dimensional array. So the array's first entry would be an array holding companyName and imageNumber, and so on.
With this implementation, numberOfSectionsInTableView would simply return myArray.count and numberOfRowsInSection would return myArray[section].count.
To access the appropriate values from there, you would do something like ((NSMutableArray*)myArray[indexpath.section])[indexpath.row]
You must use a Array of NSDictionary items,
then you get info for sections and tables rows.
adding a key for each record type.
This is a sample project for explain the use of NSArray and NSDictonary, I hope this help you.
You can download the xcode project from here http://www.germinara.it/download/FGTestTableView.zip and this is the result of the sample http://www.germinara.it/download/FGtesttableview.png
#import <UIKit/UIKit.h>
#interface FGViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> {
NSMutableArray* records;
}
#property(nonatomic,strong) IBOutlet UITableView *tblRecordsList;
-(void) buildDataSource; //Build the datasource for the tableview
#end
#import "FGViewController.h"
#interface FGViewController ()
#end
#implementation FGViewController
#synthesize tblRecordsList;
- (void)viewDidLoad
{
[super viewDidLoad];
records = [[NSMutableArray alloc] init];
//Load data into array used as datasource
[self buildDataSource];
self.tblRecordsList.dataSource=self;
self.tblRecordsList.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//Load sample data
-(void) buildDataSource{
NSMutableDictionary* dict= nil;
[records removeAllObjects];
//Fill data source with your data
//Data to put on first section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"0" forKey:#"idsection"];
[dict setObject:#"company1" forKey:#"companyName"];
[dict setObject:#"picture1" forKey:#"imageNumber"];
[records addObject:dict]; //Add items to array
//Data to put on second section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"1" forKey:#"idsection"];
[dict setObject:#"address1" forKey:#"companyAdress"];
[dict setObject:#"zip1" forKey:#"companyZip"];
[dict setObject:#"city1" forKey:#"companyCity"];
[records addObject:dict]; //Add items to array
//Data to put on other section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"2" forKey:#"idsection"];
[dict setObject:#"facebook1" forKey:#"companyFacebook"];
[dict setObject:#"phone1" forKey:#"companyPhoneNumber"];
[dict setObject:#"twitter1" forKey:#"companyTwitter"];
[dict setObject:#"website1" forKey:#"companyWebsite"];
[records addObject:dict]; //Add items to array
}
//Get Dictionary using section key (idsection)
-(NSDictionary *) dictionaryForSection:(NSInteger) section{
for (NSDictionary *dict in records){
if(section == [[dict valueForKey:#"idsection"] intValue]){
return dict;
}
}
return nil;
}
//Table View Delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"myCellReuseID"];
NSDictionary * dict = [self dictionaryForSection:indexPath.section]; //Get request dictionary info
//Process data for first section
if(indexPath.section == 0){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyName"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"imageNumber"];
}
//Process data for second section
if(indexPath.section == 1){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyAdress"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"companyZip"];
if(indexPath.row == 2)
cell.textLabel.text=[dict valueForKey:#"companyCity"];
}
//Process data for other section
if(indexPath.section == 2){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyFacebook"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"companyPhoneNumber"];
if(indexPath.row == 2)
cell.textLabel.text=[dict valueForKey:#"companyTwitter"];
if(indexPath.row == 3)
cell.textLabel.text=[dict valueForKey:#"companyWebsite"];
}
return cell;
}
//Number of sections (first,second and other => 3)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSString *)tableView:(UITableView *)theTableView titleForHeaderInSection:(NSInteger)section
{
NSString * sectionTitle =#"";
switch (section) {
case 0:
sectionTitle = #"title first section";
break;
case 1:
sectionTitle = #"title second section";
break;
case 2:
sectionTitle = #"title other section";
break;
default:
break;
}
return sectionTitle;
}
//Count number of record for sections
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int nRecords=0;
int idSection =0;
//Count number of items for specified section
for (NSDictionary *dict in records){
idSection = [[dict valueForKey:#"idsection"] intValue];
if(section == idSection){
nRecords = [[dict allKeys] count] -1 ; //All dictionary Keys - 1 (the first key "idsection")
}
}
return nRecords;
}
#end

Array out of bounds error when using UISearchDisplayController

I have a UISearchDisplayController on a UITableView. The UITableView grabs JSON data from a server, breaks it down, and an object class takes that data and creates objects. It adds the Objects to a Mutable array to then use as the datasource for the table.
There is also another Mutable array used as the 'filtered' objects.
It's declared like so:
self.filteredItems = [NSMutableArray arrayWithCapacity:[self.items count]];
When I try to search the table I get this error:
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
This is the code I'm using to do the filtering, which I found after going through a bunch of tutorials, I can't use NSPredicate because it seems the return function returns an NSArray, and I have an NSMutableArray, which I can not change because i'm not declaring the objects statically.
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
/*
Update the filtered array based on the search text and scope.
*/
[self.filteredItems removeAllObjects];
for (Update *update in items)
{
if ([scope isEqualToString:#"Serial Number"]) {
NSComparisonResult result = [[update Serial_Number] compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame){
[filteredItems addObject:update];
}
} else if ([scope isEqualToString:#"Ticket Number"]) {
NSComparisonResult result = [[update Ticket_Number] compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame){
[filteredItems addObject:update];
}
} else if ([scope isEqualToString:#"Customer"]) {
NSComparisonResult result = [[update Customer] compare:searchText options:NSCaseInsensitiveSearch range:NSMakeRange(0, [searchText length])];
if (result == NSOrderedSame){
[filteredItems addObject:update];
}
}
}
}
Not too sure what I'm doing wrong, I've never tried to implement this control before.
I actually ran break points, I can see that the objects are getting added to the filtered array, but then suddenly it crashes.
If you need any other part of the code to help me please let me know.
Thank you!
Edit:
Here's the delegate methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (updatesTableView == self.searchDisplayController.searchResultsTableView) {
return [self.filteredItems count];
} else {
return [self.items count];
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
Update *update = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
update = [filteredItems objectAtIndex:indexPath.row];
} else {
// Configure the cell...
update = [items objectAtIndex:indexPath.row];
}
[[cell textLabel] setText:[update Serial_Number]];
[[cell detailTextLabel] setText:[NSString stringWithFormat:#"Customer: %#", [update Customer]]];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.detailTextLabel.adjustsFontSizeToFitWidth = YES;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
The normal table displays just fine as well as their detail views.
In your delegate methods you have in 'numberOfRows':
if (updatesTableView == self.searchDisplayController.searchResultsTableView) {
then in 'cellForRowAtIndexPath':
if (tableView == self.searchDisplayController.searchResultsTableView) {
You're comparing different tables for determining the number of rows and then which array to get the data from.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.filteredItems count];
} else {
return [self.items count];
}
}

Insert rows to UITableView crash

Im developing an app, need to load some data in background , then show the data using UITableView.
Here are some codes,
loading data in background:
- (void)loadRelatedItems
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (NSString *mediaType in allMediaTypes)
{
[self performSelector:#selector(loadRelatedItems:) withObject:mediaType];
}
NSString *notificationName = [CommonFunction allRelatedItemsLoadedNotificationName];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:nil];
[pool release];
}
- (void)loadRelatedItems:(NSString *)mediaType
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (NSString *keyword in _keywords)
{
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#&mediaType=%#&keyword=%#", API, mediaType, keyword]];
NSMutableArray *items = [CommonFunctions arrayFromURL:URL];
if ([items count] == 0) continue;
NSString *notificationName = [CommonFunction partialRelatedItemsLoadedNotificationName];
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:items, #"items", mediaType, #"mediaType", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:self userInfo:dic];
}
[pool release];
}
showing the data in UITableView:
- (void)didFinishLoadPartialRelatedItems:(id)sender
{
NSDictionary *dic = [sender userInfo];
NSString *mediaTypeString = [dic objectForKey:#"mediaType"];
NSMutableArray *items = [dic objectForKey:#"items"];
dispatch_async(dispatch_get_main_queue(), ^{
if ([_relatedItems count] == 0)
{
[_relatedItems setObject:items forKey:mediaTypeString];
[_tableView reloadData];
}
else
{
NSMutableArray *mediaTypeItems = [_relatedItems objectForKey:mediaTypeString];
if (mediaTypeItems)
{
// section exist
NSInteger section =[[[_relatedItems allKeys] sortedArrayUsingSelector:#selector(mediaTypeCompare:)] indexOfObject:mediaTypeString];
NSMutableArray *indexPaths = [NSMutableArray array];
for (NSMutableDictionary *item in items)
{
[mediaTypeItems addObject:item];
NSInteger newRow = [mediaTypeItems indexOfObject:item];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:newRow inSection:section];
[indexPaths addObject:newIndexPath];
}
[_tableView beginUpdates];
[_tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
[_tableView endUpdates];
}
else
{
// new section
[_relatedItems setObject:items forKey:mediaTypeString];
NSInteger section =[[[_relatedItems allKeys] sortedArrayUsingSelector:#selector(mediaTypeCompare:)] indexOfObject:mediaTypeString];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
[_tableView beginUpdates];
[_tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationNone];
[_tableView endUpdates];
}
}
});
}
#pragma mark -
#pragma mark Table Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if ([_relatedItems count] == 0) {
return 1;
} else {
return [_relatedItems count];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSArray *allTitles = [[_relatedItems allKeys] sortedArrayUsingSelector:#selector(mediaTypeCompare:)];
NSString *title = [allTitles objectAtIndex:section];
NSDictionary *allMediaTypeDisplayNames = [CommonFunction allMediaTypeDisplayNames];
return [allMediaTypeDisplayNames objectForKey:title];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([_relatedItems count] == 0) {
return 0;
}
NSArray *allTitles = [[_relatedItems allKeys] sortedArrayUsingSelector:#selector(mediaTypeCompare:)];
NSString *title = [allTitles objectAtIndex:section];
NSInteger rowsCount = [[_relatedItems objectForKey:title] count];
return rowsCount;
}
I'm very confused that it works fine some times, but some times it crashed with message:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1030
*** 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 (0) must be equal to the number of sections contained in the table view before the update (2), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).
What's the problem? please help.
Please make sure after updating, your number of sections should be equal to number of sections before the update.
As per your code :
the number of sections are defined as like this:
if ([_relatedItems count] == 0) {
return 1;
} else {
return [_relatedItems count];
}
and in this case you are creating new section right ?
else { // new section
[_relatedItems setObject:items forKey:mediaTypeString];
NSInteger section =[[[_relatedItems allKeys] sortedArrayUsingSelector:#selector(mediaTypeCompare:)] indexOfObject:mediaTypeString];
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
[_tableView beginUpdates];
[_tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationNone];
[_tableView endUpdates];
}
If you are creating new section then your [_relatedItems count] is increasing. So, please make sure after the inserting also your count should be same.
Right ?
Try This :
if ([_relatedItems count] == 0) {
return 1;
} else {
if([_relatedItems count]>previousCount)
return [_relatedItems count];
return previousCount;
}
when ever you are making any updates to the [_relatedItems]; then change update your previousCount also.. this will be solved
I think your problem is with the number of rows method in the datasource just do one thing define int noOfRows in your .h file .assign your table view array count with the noOfRows. noOfRows=[yourtableArray count];
then return noOfRows from table views numberOfRowsInSection method.
Add 1 to noOfRows if you insert row in the table.
Make noOfRows-- when you delete row from the table
You will not get this exception .Update your array as per your requirement.

Deleting records in UITableViewController throws error

Problem: When I click the delete button for a given table/section row, i get the following 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 (4) must be equal to the number of rows contained in that section before the update (4), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'"
From other posts I have read about this symptom, I gather I am suppose to be manually removing an element in my datasource array, but not sure how to access the section's array inside this method:
// COMMIT EDITING STYLE
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"indexPath: %#", indexPath);
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates]; // throws error here
[tableView reloadData];
}
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
}
}
I think the complication for this situation arises due to the fact that the plist (FormEntries.plist) I am pulling data from holds user input for all sorts of things all through out my app, thus I am having to call and filter it for every section. This works fine to populate the UITableView and all of it's sections, but because a new filtered array is being created for and inside each section, I'm not sure how to ever access it again in order to remove the element, thus rectifying the above error message. Here is how I am loading the data for each table section:
// CELL FOR ROW AT INDEXPATH
- (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];
}
NSNumber *numScreenId = [[arrayOfModulesScreens objectAtIndex: indexPath.section] objectForKey: #"id"];
NSMutableArray *arrayRecords = [epFrameWork selectPlist: #"FormEntries" filterByKey: #"screen_id" keyValue:numScreenId];
NSString *strTitle = [[arrayRecords objectAtIndex: indexPath.row] objectForKey: #"storage_string"];
cell.textLabel.text = strTitle;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-- Not sure if this will help diagnose things, but here it is none the less ---
// TITLE FOR HEADER IN SECTION
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[arrayOfModulesScreens objectAtIndex: section] objectForKey: #"screen_title"];
}
// NUMBER OF SECTIONS IN TABLE VIEW
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrayOfModulesScreens count];
}
// NUMBER OF ROWS IN SECTION
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSNumber *numScreenId = [[arrayOfModulesScreens objectAtIndex: section] objectForKey: #"id"];
NSMutableArray *arrayRecords = [epFrameWork selectPlist: #"FormEntries" filterByKey: #"screen_id" keyValue:numScreenId];
int rowCount = [arrayRecords count];
return rowCount;
}
What is the best approach to handle this situation or to resolve the above posted error message?
-- UPDATE --
So here is how I'm trying to identify which plist record to delete, assuming that's what I need to do to resolve the original error:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
int g = indexPath.row;
int count = -1;
UITableViewCell *tvc = [[UITableViewCell alloc] init];
for(id element in tableView.subviews) {
if([element isKindOfClass:[UITableViewCell class]]) {
count +=1;
NSLog(#"g: %d - count: %d", g , count);
if(count == g) {
tvc = element;
NSLog(#"tvc: %# - UID: %# - g: %d - count: %d", tvc, tvc.detailTextLabel.text, g , count);
}
}
}
My logic here was to set a hidden unique identifier on tvc.detailTextLabel.text in the cellForRowAtIndexPath method, which in turn would let me know which record from the plist to filter and delete by calling [array removeObjectAtIndex:uid] where array is my filtered plist array. Only problem now is that tvc in the NSLog always returns the record at index 0, not the row that holds the delete button I click.
NSLog returns: tvc: < UITableViewCell: 0x713e2c0; frame = (0 30; 320 44); text = 'Church A'; autoresize = W; layer = < CALayer: 0x7113e70 > > - UID: -237206321 - g: 3 - count: 3. So why would tvc return the index 0 when it was index 3 I clicked the delete button?
Is this just becoming a clustered mess or is there a cleaner solution? But ya, still stumped.
This error most definitely relates to your mishandling the data that you are trying to load to your table. I found that the easiest and safest way to handle modifying table content is to do something along those lines, with the necessary adjustments (within tableView:commitEditingStyle:)
//REMOVE A CELL FROM A SECTION
[yourTable beginUpdates];
[yourTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
[yourTable endUpdates];
[yourTable reloadData];
In addition you need to make sure that your array is properly updated to have the changes reflected in the table.
This is how I was finally able to resolve the issue:
I changed all of this crap:
int g = indexPath.row;
int count = -1;
UITableViewCell *tvc = [[UITableViewCell alloc] init];
for(id element in tableView.subviews) {
if([element isKindOfClass:[UITableViewCell class]]) {
count +=1;
NSLog(#"g: %d - count: %d", g , count);
if(count == g) {
tvc = element;
NSLog(#"tvc: %# - UID: %# - g: %d - count: %d", tvc, tvc.detailTextLabel.text, g , count);
}
}
}
to one simple line:
UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath];
This allowed me to identify the cell I was working with. So my final code that worked looks like this:
// COMMIT EDITING STYLE
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath];
[epFrameWork deleteRecordFromPlist:#"FormEntries" uid:cell.detailTextLabel.text];
[tableView reloadData];
}
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
}
}
-(void) deleteRecordFromPlist:(NSString *)plist uid:(NSString *)uId {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tmpFileName = [[NSString alloc] initWithFormat:#"%#.plist", plist];
NSString *path = [documentsDirectory stringByAppendingPathComponent:tmpFileName];
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSDictionary *dict = [[NSDictionary alloc] init];
NSString *tmpUid;
for(int i=0; i < [array count]; i++) {
dict = [array objectAtIndex:i];
tmpUid = [dict valueForKey:#"uid"];
if([tmpUid isEqualToString:uId]) {
[array removeObjectAtIndex:i];
[array writeToFile:path atomically:YES];
}
}
}

When empty field comes, removed the row in the Grouped Table view in iPhone?

I have displayed the datas in grouped table view. The data's are displayed in the table view from XML parsing. I have 2 section of the table view, the section one has three rows and section two has two rows.
section 1 -> 3 Rows
section 2 - > 2 Rows.
Now i want to check, if anyone of the string is empty then i should remove the empty cells, so i have faced some problems, if i have removed any empty cell, then it will changed the index number. So how can i check, anyone of the field is empty?, Because some times more number of empty field will come, so that the index position will be change. So please send me any sample code or link for that? How can i achieve this?
Sample code,
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
if([userEmail isEqualToString:#" "] || [phoneNumber isEqualToString:#" "] || [firstName isEqualToString:#" "])
{
return 2;
}
else {
return 3;
}
}
if (section == 1) {
if(![gradYear isEqualToString:#" "] || ![graduate isEqualToString:#" "]) {
return 1;
}
else
{
return 2;
}
return 0;
}
Please Help me out!!!
Thanks.
As per my understanding, you dont want to add the row where data is empty, so ill suggest you should perpare the sections data before telling the table view about the sections and rows.
So, may be following code can help you..., i have tested it you just need to call the method "prepareSectionData" from "viewDidLoad" method and define the section arrays in .h file.
- (void) prepareSectionData {
NSString *userEmail = #"";
NSString *phoneNumber = #"";
NSString *firstName = #"";
NSString *gradYear = #"";
NSString *graduate = #"";
sectionOneArray = [[NSMutableArray alloc] init];
[self isEmpty:userEmail]?:[sectionOneArray addObject:userEmail];
[self isEmpty:phoneNumber]?:[sectionOneArray addObject:phoneNumber];
[self isEmpty:firstName]?:[sectionOneArray addObject:firstName];
sectionTwoArray = [[NSMutableArray alloc] init];
[self isEmpty:gradYear]?:[sectionTwoArray addObject:gradYear];
[self isEmpty:graduate]?:[sectionTwoArray addObject:graduate];
}
-(BOOL) isEmpty :(NSString*)str{
if(str == nil || [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0)
return YES;
return NO;
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section == 0){
return [sectionOneArray count];
} else if (section == 1) {
return [sectionTwoArray count];
}
return 0;
}
// Customize the appearance of table view cells.
- (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(indexPath.section == 0){
cell.textLabel.text = [sectionOneArray objectAtIndex:indexPath.row];
} else if (indexPath.section == 1) {
cell.textLabel.text = [sectionTwoArray objectAtIndex:indexPath.row];
}
return cell;
}
#Pugal Devan,
Well, you can keep the data in one array, but the problem in that case is, you have to take care of array bounds and correct indexes for different sections. For each section indexPath.row will start from index 0, and if your data is in single array, you have to manage the row index by your self. But still if you want to keep it, you can do like:
int sectionOneIndex = 0;
int sectionTwoIndex = 3;
NSMutableArray *sectionArray = [[NSMutableArray alloc] initWithObjects:#"email", #"Name", #"address", #"zipCode", #"country", nil];
Above two integers represents the starting position of elements of your different sections. First 3 objects from the section Array are the part of section One, and last two objects are the part of section two. Now you need to return correct row count.
For that you may write:
if(section == 0) return [sectionArray count] - (sectionTwoIndex-1); //returns 3
else if(section == 1) return [sectionArray count] - sectionTwoIndex; //returns 2
OR if your count is static you may put constant values in return.
And at the time you read from array, you will just add this index in row value, which will return the correct position of your element for the current cell.
// Customize the appearance of table view cells.
- (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(indexPath.section == 0){
cell.textLabel.text = [sectionArray objectAtIndex:indexPath.row + sectionOneIndex];
} else if (indexPath.section == 1) {
cell.textLabel.text = [sectionArray objectAtIndex:indexPath.row + sectionTwoIndex];
}
return cell;
}