3 tables on ipad with different data - objective-c

Im trying to implement 3 different table views that load 3 different arrays of information,
In some forum I read that I could use the .tag to differentiate the tables and use conditionals to load the data,
I tried
changing the name of the table
in identity /name of the xib to my table,
and use
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
//---try to get a reusable cell---
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//---create new cell if no reusable cell is available---
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
/*
//---set the text to display for the cell---
NSString *cellValue = [listOfMovies objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue; */
if (tableView.tag == 1) {
//Deal with table 1 - contains 5 sections
cell.textLabel.text = [array objectAtIndex:indexPath.row];
} else if (tableView.tag == 2) {
//Deal with table 2 - contains 1 section
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
}
// cell.textLabel.text = [array3 objectAtIndex:indexPath.row];
else {
cell.textLabel.text = [array objectAtIndex:indexPath.row];
}
return cell;
}
to change the cell content to show the other array
but is not working (long shot!)
so, How to define this .tag for my tables
also, I want the same for row (count) and sections 1
for all the tables,
so shall I just leave them like that??
I have the 3 tables showing the same array at the moment,
thank you so much!

Um, haven't tried this, but I'd be inclined to look into associating each table view with it's own unique UITableViewDataSource instance. That way they do not have to be all coded in the same class and everything becomes simpler. Not sure how you would go about assembling this, but it should be too hard to work out I would think.

I think you're over-complicating things. In one of my apps I have one table view controller for three tables. The interface definition is something like:
#interface TableViewController : UITableViewController <UIGestureRecognizerDelegate> {
IBOutlet UITableView *leftTable;
IBOutlet UITableView *centerTable;
IBOutlet UITableView *rightTable;
...
Then, in each of the delegate methods, I check to see which table it is before performing the relevant action or returning the relevant result. For example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == leftTable) {
return [self.leftItems count];
} else if (tableView == centerTable) {
return [self.centerItems count];
} else {
return [self.rightItems count];
}
}

Related

Obj C - populate TableView with objects at specific indexes in array

I want to populate my TableView with objects from my array at specific indexes. I thought I could do this by looping an insertObject line and adding the objects that I want to populate the TableView with (at the specific indexes) to a new array and then populating the tableView with the new array but at the end the new array is nil.
The first array is layout like this: email, name, key code, email, name, key code, email, name, key code, etc...... So i want to fill the second array with just the keycodes and then use the key code array and fill the table with it
This is what I have so far:
.h
#property(nonatomic) NSArray *productList;
#property(nonatomic) NSMutableArray *productKeycodes;
.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
// If You have only one(1) section, return 1, otherwise you must handle sections
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
// Return the number of rows in the section.
return [self.productList count] / 3;
}
- (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];
}
self.productKeycodes = [NSMutableArray new];
bool flag = true;
int index = 3;
int arraySize = [self.productList count];
int numberOfKeycodes = [self.productList count] / 3;
while (flag) {
self.productKeycodes = [self.productList objectAtIndex: index];
//[self.productKeycodes insertObject: self.productList atIndex: index];
if (arraySize > numberOfKeycodes) {
index = index + 3;
arraySize = arraySize - 3;
}else{
flag = false;
}
}
cell.textLabel.text = [NSString stringWithFormat:[self.productKeycodes objectAtIndex: indexPath.row]];
return cell;
}
Breakpoint data after loop is done:
self ProductListViewController * 0x7a2831c0
UIViewController UIViewController
_productListTableView UITableView * 0x7b30c400
_productList __NSArrayM * #"49 elements" 0x78ebe380
_productKeycodes NSMutableArray * nil 0x00000000
numberOfKeycodes int 16
index int 26
arraySize int 13
flag bool true
At get a signal SIGABRT error here:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
//The line below
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));//Here!
//The line above
}
}
is my logic wrong and/or is there a better way to do this? Thanks!
replace all code in tableView:cellForRowAtIndexPath: with this:
- (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];
}
cell.textLabel.text = self.productList[indexPath.row * 3 + 2];
return cell;
}
//
Your logic is wrong.
When you want to add something to the table view you need to do it as follows:
Update you data source i.e. productList in your case.
When you are finished updating the data source, call self.tableView.relaodData()
That is all you need to do to insert data to UITableView
There are better ways to do this
Why do you divide count by 3 and mess with index and flags?
It's ok if you have a good reason but the code to populate your tableview should not belong in cellForRowAtIndexPath.
It is not so clear what you are trying to achieve but the correct way is to update your data source and reload the tableView.
You can create an array of your desired indexes. then in cellForRowAtIndexPath. get the data this way:
int data = datas[indexes[indexPath.row]];
I hope you get the idea

How to populate multiple table view sections from the same .plist

Sorry if this has been discussed already, I couldn't find what I was after..
I have a .plist file which has 2 arrays in it, which are split exactly how I would like my sections split in my table view.
I have no problem getting an array into a table view, but I cant get my head around how to tell the app that I want one array in the first section and the second array in the second section.
My code at the moment to get an array into a table is this (and it works fine):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Create string with reference to the prototype cell created in storyboard
static NSString *CellIdentifier = #"PlayerNameCell";
//Create table view cell using the correct cell type
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Create a dictionary containing the player names
NSDictionary *players = (NSDictionary*) [[self Squad] objectAtIndex:[indexPath row]];
//Set the cell text to the player name
[[cell textLabel] setText:(NSString*)[players valueForKey:#"PlayerFullName"]];
//Set the cell detail text to the squad number
[[cell detailTextLabel] setText:(NSString*)[players valueForKey:#"PlayerSquadNumber"]];
return cell;
}
But now I have another table view where I'll need 2 sections, each reading from different arrays.
Any help would be greatly appreciated.
Many thanks
Just do the following:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
{
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"PlayerNameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if( cell == nil ){
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if( indexPath.section == 0 ){
NSDictionary *players = (NSDictionary*) [self.array1 objectAtIndex:indexPath.row];
cell.textLabel.text = (NSString*)[players valueForKey:#"PlayerFullName"];
cell.detailTextLabel.text = (NSString*)[players valueForKey:#"PlayerSquadNumber"];
} else {
NSDictionary *players = (NSDictionary*) [self.array2 objectAtIndex:indexPath.row];
cell.textLabel.text = (NSString*)[players valueForKey:#"PlayerFullName"];
cell.detailTextLabel.text = (NSString*)[players valueForKey:#"PlayerSquadNumber"];
}
return cell;
}
Set the number of sections to 2. For each section get the different values with [self.array2 objectAtIndex:indexPath.row].
I don't know how you are saving the plist into 2 arrays, but if you need help with that let me know.
Okay, so you have 2 arrays at the top level, and each of those arrays contains arrays, right?
You've got a couple methods you need to adjust. Return the number of top level arrays for the number of sections in the table view. In cellForRowAtIndexPath:, return the correct object for the correct section/row. Something like
[[sectionsArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]

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

hardcoded Tablecells in section 0, core-data fetched-results in section 1

my problem ist that i have UITableView with two sections.
In the first section i have objects of a NSArray and the second section should be filled with core-data results.
But if i use the fetchedResultsController it sets the section of his data to 0 and not to 1 as i need.
So cellForIndexPath uses the indexPath, and if i want to display the core-data in section 1 the fetchedResultsController doesn't find data.
My current workaround is
if (indexPath.section == 1) {
NSIndexPath *temp = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section-1];
and then use temp instead of indexPath.
But it's very ugly to check in every UITableView function if the section==1.
Is there a better way to get the fetched results directly in section 1?
Thank you very much!
Seega
Warning this is a Kludge:
add a "sectionKludge" value to your Entity and instantiate a dummy version of this Entity with a value of 0 for sectionKludge (ignore this ManagedObject, you will not see it in your table) and then instantiate all of the real Entity's with a value of 1 (you could even make this the default value for this optional property). In your FRC set the sectionNameKeyPath to "sectionKludge" and then use Rog's answer.
I have groaned about doing what you are asking in several of the table views that I have in apps that I write... I usually just back down and manually fool with the array and not use an FRC.
I would just adjust the NSIndexPath like you are saying and be done with it.
Your fetchedResultsController doesn't determine WHERE the fetched data is going to be inserted, this is up to your tableview dataSource methods to work out based on logic that you put in place.
I don't have all the details of your implementation but the below should roughly do what you are trying to achieve. You simply need to test for the (section) value in certain parts of your code to work out how you are going to fill the data for sections and rows.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath == kSectionZero) {
// Configure cell with data from NSArray here
} else {
NSManagedObject *yourObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
// Configure cell with data from *yourObject here
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSUInteger count = [[self.fetchedResultsController sections] count];
return count + X; // where X == number of additional sections you want, in your case X == 1
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 1) {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects]
} else return [arrayObject count]
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == 1) {
NSString *sectionName = [[[self.fetchedResultsController sections] objectAtIndex:section] name];
return sectionName;
} else return #"Whatever section name you want for section == 0 here";
}
}

TableView returns null (0) when selecting row

I have a TableView control which I've sectioned/grouped. However this has now broken the code which determines the item I've selected in the Table.
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
*/
//detailViewController.detailItem = [NSString stringWithFormat:#"Row %d", indexPath.row];
if (_delegate != nil) {
Condition *condition = (Condition *) [_conditions objectAtIndex:indexPath.row];
[_delegate conditionSelectionChanged:condition];
}
}
My sample data currently has 6 sections, the first one contains two items with all the rest containing one. If I select the second item in the first section, the details view updates fine, any other selection always shows the first item in the first section (item 0).
I'm assuming this is because indexPath.row is returning 0 for the other sections as it's the first item in that section, which is then causing the first object from my array to be chosen.
How do I fix my code to ensure the correct item is selected? Everything else works fine other than this.
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
//get the letter in the current section
NSString *alphabet = [conditionIndex objectAtIndex:[indexPath section]];
//get all conditions beginning with the letter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name beginswith[c] %#", alphabet];
NSArray *conditionsGrouped = [_conditions filteredArrayUsingPredicate:predicate];
if ([conditionsGrouped count] > 0) {
Condition *condition = [conditionsGrouped objectAtIndex:indexPath.row];
cell.textLabel.text = condition.name;
}
return cell;
}
You should take into account indexPath.section, as well.
You should create a bi-dimensional _conditions array, indexed by section and then by row.
Got it working by following the answer at this post:
UITableView Problem with Sections