Initialize UITableView with dynamic data - objective-c

I am trying to display a list of friends in a UITableView.
I am loading the friends:
- (void)viewDidLoad
{
[super viewDidLoad];
[self apiGraphFriends];
}
Then I am setting my results in:
- (void)request:(FBRequest *)request didLoad:(id)result
{
friends = [[NSMutableArray alloc] initWithCapacity:1];
NSArray *resultData = [result objectForKey:#"data"];
if ([resultData count] > 0) {
for (NSUInteger i=0; i<[resultData count]; i++) {
[friends addObject:[resultData objectAtIndex:i]];
}
} else {
//[self showMessage:#"You have no friends."];
}
}
and I am implementing the required UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [friends count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
//NSManagedObjectModel *friend [fetch
FriendCell *cell = [tableView dequeueReusableCellWithIdentifier: #"friendCell"];
cell.cellName.text = [friends objectAtIndex:indexPath.row];
return cell;
}
The problem is that the method 'cellForRowAtIndexPath' is being called before my data has arrived, how do you prevent the automatic initialization of the table view and only initialyse it when you have data for it ?

The tableview is always loaded on launch. Instead, after the data has finished loading, call
[self.tableView reloadData];
This tells the tableView to refresh, and it calls cellForRowAtIndexPath and all that jazz again.

how do you prevent the automatic initialization of the table view
You don't. The table view will automatically try to load its data when it is created and displayed. But that should not be a problem.
and only initialyse it when you have data for it.
Send a reloadData message to the table view once the data is ready.

Have you remembered to change the number of sections from 0 to at least 1?
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
To fully test this you can use the following code
- (void)viewDidLoad
{
[super viewDidLoad];
//Add your friend as you initialise the array
NSMutableArray *array = [NSMutableArray arrayWithObjects:f1,nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.friends count];
}
- (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];
}
//change this to whatever you need
NSString *friend = [self.friends objectAtIndex:indexPath.row];
cell.textLabel.text = friend;
return cell;
}

Your numberOfRowsInSection should return 0 if you don't have anything to display. After the data is loaded and ready to display, you should call reloadData on the tableView, and only then should the data be displayed. numberOfRowsInSection should now give the number of rows you loaded.
In short, you don't prevent the tableView from initializing. You initially tell it to display no data, and once your data is loaded, you tell it to display as many rows as you have.

Don't set the tableview delegate and datasource until AFTER you have your data.
i.e.
-(void)viewDidLoad{
[self apiGraphFriends];
self.tableview.delegate = self;
self.tableview.datasource = self;
}
I am assuming your method 'apiGraphFriends' doesn't use any background threading and isn't asynchronous. If it is, then just create a new method and put the datasource/delegate setting in there, then call it from a block in your apiGraphFriends method.

simply call reloadData of the tableView once you got your data, the tableview will reload its data and thus recall all your datasource methods to get its data.

You are so close!
- (void)viewDidLoad
{
[self apiGraphFriends];
[super viewDidLoad];
}
That should do it. If not, you can always call reloadData on the tableView.

Related

Multiple selection to array.

My problem is that I load players from database to UITableView and i want to store this players in Array but I provide multiple selection. Next I want so save this information to DB. I have done DB layer so just need information how to store this multiple selected players to array.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.cellSelected = [NSMutableArray array];
self.selectedItems = [NSMutableArray array];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//Cell Initialisation here
if ([self.cellSelected containsObject:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//if you want only one cell to be selected use a local NSIndexPath property instead of array. and use the code below
//self.selectedIndexPath = indexPath;
//the below code will allow multiple selection
if ([self.cellSelected containsObject:indexPath])
{
[self.cellSelected removeObject:indexPath];
[self.selectedItems removeObject:[self.selectedItems indexOfObject:[self.dataArray objectAtIndex:indexPath.row]]];
}
else
{
[self.cellSelected addObject:indexPath];
[self.selectedItems addObject:[self.dataArray objectAtIndex:indexPath.row]];
}
[tableView reloadData];
}
Where your data array hold data from database (Whole players information). selectedItems array contains the details of selected player info.
Hope this helps :)

cellForRowAtIndexPath returns null but really need similar method

I have a UITableView in my UITableViewController (lol, obviously) but I need to get a cell at a given index inside the - (void)viewWillAppear:(BOOL)animated method.
Now, my cells are static and I create them in the interface builder. If I call
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:previously_selected_cell.integerValue inSection:0]];
it returns null for the cell. I only have 3 static cells in 1 sections. I tried both sections 0 and 1 and both return null.
Currently I have removed the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method because if I add it, it will clear the UITableView of all my static cells.
Is there a method I can call in - (void)viewWillAppear:(BOOL)animated that will return a cell at a given index?
Thanks in advance!
EDIT: I checked out this stackoverflow question but I'm using static cells without cellForRowAtIndexPath so that question didn't help. :(
EDIT2: I'm trying to set the accessory type of the cell when the view loads. But only on a certain cell, that cell being the one the user selected before he quit the app.
#import "AutoSyncSettings.h"
#import "CDFetchController.h"
#implementation AutoSyncSettings
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
CDFetchController *cdfc = [[CDFetchController alloc] init];
NSFetchedResultsController *results = [cdfc getFetchedResultsControllerWithEntityName:#"SETTINGS"];
NSArray *objects = [results fetchedObjects];
NSNumber *sync_setting;
if(objects.count > 0)
{
NSManagedObject *object = [objects objectAtIndex:0];
sync_setting = [object valueForKey:#"wifi_setting"];
NSLog(#"(Settings)sync_setting: %#",sync_setting);
NSLog(#"(Settings)sync_setting int value: %i",sync_setting.integerValue);
NSLog(#"(Settings)TableView: %#",self.tableView);
//cell is null, even after this.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:wifi_settings.integerValue inSection:0]];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//cell is still null. WHY OH WHY? :(
objects = nil;
}
cdfc = nil;
results = nil;
objects = nil;
sync_setting = nil;
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
for (int i = 0; i < [tableView numberOfRowsInSection:indexPath.section]; i++)
{
if([[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:indexPath.section]] accessoryType] == UITableViewCellAccessoryCheckmark)
{
[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:indexPath.section]].accessoryType = UITableViewCellAccessoryNone;
}
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
CDFetchController *cdfc = [[CDFetchController alloc] init];
NSFetchedResultsController *results = [cdfc getFetchedResultsControllerWithEntityName:#"SETTINGS"];
NSManagedObjectContext *context = [results managedObjectContext];
NSArray *objects = [results fetchedObjects];
if(objects.count > 0)
{
NSManagedObject *object = [objects objectAtIndex:0];
NSNumber *sync_setting = [NSNumber numberWithInt:indexPath.row];
[object setValue:sync_setting forKey:#"sync_interval"];
[object setValue:[NSNumber numberWithInt:0] forKey:#"id"];
[ErrorHandler saveMoc:context];
}
else
{
//INSERT NEW OBJECT
NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:#"SETTINGS" inManagedObjectContext:context];
NSNumber *sync_setting = [NSNumber numberWithInt:indexPath.row];
[object setValue:sync_setting forKey:#"sync_interval"];
[object setValue:[NSNumber numberWithInt:0] forKey:#"id"];
[ErrorHandler saveMoc:context];
}
}
#end
I have a project doing exactly this and it works perfectly. However, it doesn't work unless you call [super viewWillAppear:animated] before trying to access the cells in this manner.
The base implementation presumably loads in the cells from the storyboard.
I want to add a checkmark accessory to the previously selected cell,
the previously_selected_cell variable gets stored even if the app
quits/crashes
The way to go will be to control the indexPath in your cellForRowAtIndexPath implementation and act if it's equal to previously_selected_cell.integerValue:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// usual cache lookup, allocation of the cell, etc
if (indexPath.row == previously_selected_cell.integerValue) {
// add checkbox here
} else {
// remove checkbox
}
}

How to Programmatically Create UITableView and Populate with NSArray in Xcode 4.2?

I have been struggling to understand the difference between Storyboards and coding in Objective-C. It appears you can create a UITableView by both dragging the object into your Storyboard, or coding in a new view within Objective-C.
The problem is that I want to keep my Storyboard as slim as possible. So I'm trying to build and populate a UITableView with an NSArray of 5 strings. My code will only run 1 row before returning a compiler error... I am going to scrap the whole project and start fresh.
I would be very grateful if somebody familiar with the new Xcode 4.2/iOS5/Storyboards can provide a reasonable solution for building the UITableView. I know this is such a basic task which is why it's so frustrating to begin with. I can get the Table View working, but I cannot seem to get an Array to dynamically fill and create #X number of rows...
Let me know if I can provide any more info. I've tried to be as straightforward as possible - just need to get a TableView working and populate with an Array :)
EDIT - here is my project source code you can download to check out where I'm at.
The reason it crashes is that in the storyboard you have to change the tableview to dynamic prototypes instead of static cells.
For some reason Static Cells is the default setting. Once you get the hang of the Storyboards it's great, especially when dealing with tableviews. Your initial View is set up as the NavigationController which has your MasterviewController as the RootViewController, so it's being loaded as the firstView. Click on the TableView in the MainStoryboard and change the Cels to Dynamic Prototypes or it will use the static ones that you create right in the storyboard. You can make custom cells right on the tableview in the storyboard. One more thing to note is the re-use identifier has to be set to the same name in the storyboard and the TableViewController.
You can also just up the count of static cells to the number you want if you know it will always be the same.
Here's a trivial sample with subclassing UITableViewController populated with an NSArray (NSMutableArray) from my sample code. It doesn't use story boards but you said that's OK in your comment. Hopefully my sample code helps you.
Header:
#interface MainTableViewController : UITableViewController
{
NSMutableArray *_items;
}
#end
Implementation:
#implementation MainTableViewController
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Lifetime
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self)
{
// datastore
_items = [[NSMutableArray alloc] init];
for (int index=0; index < 5; index++)
{
[_items addObject:[NSString stringWithFormat:#"item #%d", index]];
}
}
return self;
}
- (void)dealloc
{
[_items release];
[super dealloc];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Table View DataSource
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// a typical table has one section
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// number of rows
return [_items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSIndexPath contains an array of indexes. For UITableView:
// indexAtPosition:0 is the section number
// indexAtPosition:1 is the row number
// create an identifier for this type of cell
static NSString *CellIdentifier = #"Cell";
// get a cell of this type from the re-use queue or create one
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *title = [_items objectAtIndex:[indexPath indexAtPosition:1]];
[[cell textLabel] setText:title];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
NSLog(#"delete section: %d rol: %d", [indexPath indexAtPosition:0], [indexPath indexAtPosition:1]);
[_items removeObjectAtIndex:[indexPath indexAtPosition:1]];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
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
NSLog(#"insert section: %d rol: %d", [indexPath indexAtPosition:0], [indexPath indexAtPosition:1]);
}
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSString *fromItem = [_items objectAtIndex:[fromIndexPath indexAtPosition:1]];
[_items removeObjectAtIndex:[fromIndexPath indexAtPosition:1]];
[_items insertObject:fromItem atIndex:[toIndexPath indexAtPosition:1]];
}
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UITableViewDelegate
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"selected section: %d rol: %d", [indexPath indexAtPosition:0], [indexPath indexAtPosition:1]);
// get the selected cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
// navigate to detail
DetailedTableViewController *detailedView = [[DetailedTableViewController alloc] init];
[[self navigationController] pushViewController:detailedView animated:YES];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark View lifecycle
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
[[self navigationItem] setRightBarButtonItem: [self editButtonItem]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end

Strange error: insertRowsAtIndexPaths in UITableView crashes with NSInternalInconsistencyException

I have searched for a more fitting answer to NSInternalInconsistencyException I receive in the following sample app I wrote, but still nothing. The goal is to create an expand/collapse functionality for the top row in each section of the tableView. Right now I try to implement the expand part, and this works for row 0 in section 0. As soon as the user taps row 0 in another section this error appears:
** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to resolve row for index path: 2 indexes [0, 1]'
This is strange since I store each and every UITableViewCell for the table in a mutable array of arrays. NSMutableArray *cellForRow, where each index represents a section in the table and each object is an object of type NSMutableArray. I do this to avoid any issues arising from queueing reusable cells that I first thought triggered the above exception.
The exception happens at the insertRowsAtIndexPaths statement. I read earlier here that the UITableViewController code must keep track of changes to the number of rows caused by insertions/deletion. I believe I do that with NSMutableArray *rowsInSection so that the UITableView data source method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
returns the correct number of rows in a section after a change.
What am I doing wrong in my code to get the above mentioned exception?
This is the interface file:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface MasterViewController : UITableViewController {
NSMutableArray *rowsInSection;
NSMutableArray *cellForRow;
}
#property (nonatomic,strong) NSMutableArray *rowsInSection;
#property (nonatomic,strong) NSMutableArray *cellForRow;
#end
And this is the implementation file:
#import "MasterViewController.h"
const NSInteger numSections = 4;
const NSInteger numRows = 1 + 4;
const NSInteger addRemoveRows = 4;
#implementation MasterViewController
#synthesize rowsInSection;
#synthesize cellForRow;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = #"Table View";
rowsInSection = [NSMutableArray arrayWithCapacity:numSections];
cellForRow = [NSMutableArray arrayWithCapacity:numSections];
}
return self;
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.dataSource = self;
self.tableView.delegate = self;
// add number of rows for section
for (NSInteger i = 0; i < numSections; i++) {
[self.rowsInSection addObject:[NSNumber numberWithInteger:1]];
}
// container for reusable table view cells
for (NSInteger i = 0; i < numSections; i++) {
NSMutableArray *rowsArray = [NSMutableArray arrayWithCapacity:numRows];
for (NSInteger j = 0; j < numRows; j++) {
// top row in section
if (j == 0) {
UITableViewCell *topCell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
topCell.accessoryType = UITableViewCellAccessoryNone;
topCell.contentView.backgroundColor = [UIColor whiteColor];
topCell.textLabel.textColor = [UIColor blueColor];
[rowsArray addObject:topCell];
// the rest
} else {
UITableViewCell *simpleCell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
simpleCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
simpleCell.textLabel.textColor = [UIColor whiteColor];
[rowsArray addObject:simpleCell];
}
}
// add rows for current section into cell container
[self.cellForRow addObject:rowsArray];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return numSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger rows = [(NSNumber *)[self.rowsInSection objectAtIndex:section] integerValue];
//NSLog(#"%#",self.rowsInSection);
//NSLog(#"Rows: %d in section: %d",rows,section);
return rows;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Configure the cell.
// row count
NSLog(#"Rows: %d in section: %d",[tableView numberOfRowsInSection:indexPath.section],indexPath.section);
if (indexPath.row == 0) {
UITableViewCell *cell = (UITableViewCell *)[[self.cellForRow objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.textLabel.text = #"TOP ROW";
NSLog(#"Row: %d in section: %d - %#",indexPath.row,indexPath.section,cell);
return cell;
} else {
UITableViewCell *cell = (UITableViewCell *)[[self.cellForRow objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"row: %d",indexPath.row];
NSLog(#"Row: %d in section: %d - %#",indexPath.row,indexPath.section,cell);
return cell;
}
// not reaching here
return nil;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:#"Section %d",section];
}
#pragma mark - Row editing
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// add table view cells to section if tapped on top row
if (indexPath.row == 0 && [tableView numberOfRowsInSection:indexPath.section] == 1) {
//NSLog(#"Selected row: %d in section: %d",indexPath.row,indexPath.section);
NSMutableArray *indexPathArray = [NSMutableArray array];
for (NSInteger i = 1; i <= addRemoveRows; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:indexPath.section];
[indexPathArray addObject:indexPath];
}
// update row count for section
NSInteger newRowCount = addRemoveRows + 1; // +1 for existing top row
[self.rowsInSection replaceObjectAtIndex:indexPath.section withObject:[NSNumber numberWithInteger:newRowCount]];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
}
}
#end
If you are inserting/deleting multiple rows at the same time it has to be bracketed with calls to beginUpdates/endUpdates.
The table view data source needs to be consistent with your insert/delete calls.
Set a break point in numberOfRowsInSection to assure that the number of rows in a section is correct after the insert/delete rows.
(i'm not going to read through all your code to debug it for you.)
good luck!
I was having this issue as well.
It wasn't something I was doing wrong inside the body of code, but I didn't realize an object was being inserted into my dataSource at another time. If you're getting this issue, make sure you follow bshirley's advice and stick a breakpoint on numberOfRowsInSection AND the body of code where you add the item. Make sure the number is the same amount of items in your dataSource throughout the lifecycle of adding the data. There really isn't any reason it should fail.
It is fairly simple, just make sure you're keeping your data and indexpath amounts before and after the update. Otherwise this exception will be thrown.
You are not only inserting cells, you also deleting old row, but the table view does not know about it as you haven't told it. So the table view "knows" it has one row, then you tell it you've added lets say two rows. The table view knows, that it should contain 3 rows BUT it founds only two as you've deleted the old one... What you need is or to use -(void)tableView:(UITableView)tableView deleteRowsAtIndexPaths:(NSArray)indexPath withRowAnimation:(UITableViewRowAnimation)animation; or delete one index path from array of added rows...And by the way, return to use reusable cells as it have no connection with the error you've faced...
In this method
-(void)tableView:(UITableView)tableView deleteRowsAtIndexPaths:(NSArray)indexPath withRowAnimation:(UITableViewRowAnimation)animation;
your variable NSIndexPath *indexPath is repetition with the variable of this method

Remove Gray UITableView Index Bar

I am making an application with a UITableView that has a few sections (2), and when I run, the table view has this annoying gray index bar on the side, like the one in the "iPod" application, that has but 2 options in it. My question is, how do I hide the "index bar," because it is an unnecessary waste of space?
Example:
Code snippets:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sections count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return sections;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return 2;
}
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sections objectAtIndex:section];
}
// 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.
cell.textLabel.text = [content objectAtIndex:(indexPath.row + [[sectionAmounts objectAtIndex:indexPath.section] intValue])];
tableView.showsVerticalScrollIndicator = NO;
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
content = [NSArray arrayWithObjects:#"Sphere", #"Cylinder", #"Circle", nil];
sections = [NSArray arrayWithObjects:#"3d", #"2d", nil];
sectionAmounts = [NSArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:2], nil]; //Second number is objects in first section... odd huh?
self.tableView.showsVerticalScrollIndicator = NO;
[content retain];
[sections retain];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
(Mind my odd comments...)
HiGuy
I tried this, and it didn't work for me.
so i went through the table view properties, and got this.
self.tableView.showsVerticalScrollIndicator = NO;
works like a charm.
*for any one who wants to do this in the future.
That "scroll bar" is your index bar, assuming you're talking about the giant grey thing.
Return nil from sectionIndexTitlesForTableView: and it'll go away.
I had similar issue, however had to deal with my header/footer. Essentially I just removed the following methods
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #" "; //#"Top";
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return #" "; //#"Bottom";
}
You just use the below code and gray bar will go....
tableViewBrowse.sectionIndexTrackingBackgroundColor = [UIColor clearColor];
Use sectionIndexBackgroundColor property of UITableView to set the color of index bar to clear color as hiding scroll bar is going to hide the indexes as well.
Add it to your viewDidLoad: as following:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor]; //Replace it with your desired color
}