Casting to right object for tableView cells - iphone

I'm using tableView for displaying each tam tableView with different data.
when I coming back to the interface with all the tableView delegates i'm tantalizing the *list with a data (different arrays with fields) based on the the previous view
if(select = names )...
list = myData.Names;
if (select = workers)...
list = myData.Workers;
and so on...
and in the table delegates I use:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [list count];
}
But when I initializing the object for the table cells, How can I set exatcly the right object for the cell. now hard-coded I using:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
}
//HARD-CODED
names *s = [list objectAtIndex:indexPath.row];
cell.textLabel.text = names.firstName;
cell.detailTextLabel.text=s.lastName;
return cell;
}
When i setting the list to workers how can I know to cast every time to the right object? without writing millions of if?
for example if
if (select = workers)...
list = myData.Workers;
the [list count] will return the right number but i want to display data based on the list, how can i cast it so it automatically declare workers
workers *s = [list objectAtIndex:indexPath.row];

I think I understand your problem, so let me try to explain:
This can be easily solved using protocols and giving the cell configuring responsibility to the actual objects.
First, declare a protocol that your clases will conform to:
#class MyTableViewCell;
#protocol CellConfiguring
- (void)configureCell:(MyTableViewCell *)cell;
#end
Now make some classes and make sure all of them conform to this protocol:
#interface Workers : NSObject <CellConfiguring>
#property (retain, nonatomic) NSString *company;
#property (retain, nonatomic) NSString *salary;
#end
and:
#interface Names : NSObject <CellConfiguring>
#property (retain, nonatomic) NSString *firstName;
#property (retain, nonatomic) NSString *lastName;
#end
etc...
In their implementation, each of them will handle the configuring of the cell differently:
#import "MyTableViewCell.h"
#implementation Workers
- (void)configureCell:(MyTableViewCell *)cell
{
cell.textLabel.text = self.company;
cell.detailTextLabel.text = self.salary;
}
#end
and:
#import "MyTableViewCell.h"
#implementation Names
- (void)configureCell:(MyTableViewCell *)cell
{
cell.textLabel.text = self.firstName;
cell.detailTextLabel.text = self.lastName;
}
#end
Remember the cell you receive is a custom cell that you created. For instance:
#interface MyTableViewCell : UITableViewCell
#property (retain, nonatomic) UILabel *textLabel;
#property (retain, nonatomic) UILabel *detailTextLabel;
#end
Now, in your delegate call:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
}
id myObject = [list objectAtIndex:indexPath.row];
if ([myObject conformsToProtocol:#protocol(CellConfiguring)]
[myObject configureCell:cell];
return cell;
}
And that's it. No more if-else statements and no more casting.
Tip: Whenever you start seeing too many if-else statements in your class, dirtying up your code, start thinking about responsibilities. Should the object be in charge of figuring out how to configure the cell? Or could we delegate that task to another object?

Set One flag in .h file like BOOL flag. Data will be filled according flag.
Intially flag will be TRUE in ViewDidLoad.
Now set list like this:
if()...
listNames = myData.Names;
if ()...
listWorkers = myData.Workers;
and in the table delegates:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(flag){
return [listNames count];
else
{
return [listWorkers count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
}
if(flag)
{
names *s = [listNames objectAtIndex:indexPath.row];
cell.textLabel.text = names.firstName;
cell.detailTextLabel.text=s.lastName;
return cell;
}
else
{
names *s = [listWorkers objectAtIndex:indexPath.row];
cell.textLabel.text = names.firstName; // change for listWorkers
cell.detailTextLabel.text=s.lastName; // change for listWorkers
return cell;
}
}
Now when u want to change then
flag = FALSE; //worker data will be filled
[tableView reloadData]

You might be able to use the following solution ...
Create a custom object that conforms to UITableViewDataSource for each type of object. For example WorkerDataSource, NamesDataSource, etc...
Depending on the data you want to display, set the right dataSource for the tableView. An example from a project I work on ...
#define SECTION_HEADER_HEIGHT 20.0f
#interface FSMatchProgrammeDataSource ()
#property (nonatomic, copy) NSArray *matches;
#property (nonatomic, copy) NSArray *groupedMatches;
#end
#implementation FSMatchProgrammeDataSource
#synthesize matches = _matches;
#synthesize groupedMatches = _groupedMatches;
#synthesize didSelectMatchHandler = _didSelectMatchHandler;
+ (FSMatchProgrammeDataSource *)dataSourceWithMatches:(NSArray *)matches
{
FSMatchProgrammeDataSource *dataSource = [[FSMatchProgrammeDataSource alloc] init];
if (dataSource)
{
dataSource.matches = matches;
}
return dataSource;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return _groupedMatches.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *matches = [_groupedMatches objectAtIndex:section];
return matches.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MatchProgrammeCellIdentifier";
FSMatchProgrammeCell *cell = (FSMatchProgrammeCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[FSMatchProgrammeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSArray *matches = [_groupedMatches objectAtIndex:indexPath.section];
cell.match = [matches objectAtIndex:indexPath.row];
DLog(#"%#", cell.match);
return cell;
}
#pragma mark - Table view delegate
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// custom view created here ...
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return SECTION_HEADER_HEIGHT;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44.0f;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_didSelectMatchHandler)
{
NSArray *matches = [_groupedMatches objectAtIndex:indexPath.section];
FSMatch *match = [matches objectAtIndex:indexPath.row];
_didSelectMatchHandler(match);
}
}
#pragma mark - Properties
- (void)setMatches:(NSArray *)matches
{
// matches property set, also an sorted / grouped copy is created for display called groupMatches ...
}
#end
And the dataSource is assigned in the tableViewController like this:
- (void)refreshView
{
BOOL showInfoLabel = NO;
switch (_tabBar.selectedSegmentTag)
{
case TabProgramme:
_tableView.dataSource = _programmeDataSource;
_tableView.delegate = _programmeDataSource;
break;
case TabResults:
_tableView.dataSource = _resultsDataSource;
_tableView.delegate = _resultsDataSource;
break;
case TabStandings:
_tableView.dataSource = _standingsDataSource;
_tableView.delegate = _standingsDataSource;
break;
default: break;
}
[self.tableView reloadData];
}

Related

Unable to populate UITableView from NSMutable array from another view

I have 2 VCs, first is BooksDetailViewController which has the NSString myBookString. Another on is FavBooksViewController which has the favBookList NSMutableArray. I want to pass the NSString myBookString from the 1st VC to include it in the favBookList NSMutableArray which then populates the table.
I have included #class FavBooksViewController; in the BooksDetailViewController.h
Imported #import "FavBooksViewController.h" in the BooksDetailViewController.m
The action in the BooksDetailViewController.m looks like this:
- (IBAction)addToFav:(id)sender {
FavBooksViewController *mdvc;
[mdvc.self.favBookList addObject:myBookString];
}
In FavBooksViewController.h I have
#interface FavBooksViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) id delegate;
#property (nonatomic,strong) NSMutableArray *favBookList;
In the FavBooksViewController.m - #import "FavBooksDetailViewController.h"
In the ViewDidLoad I tried to include this line
self.favBookList = [[NSMutableArray alloc]initWithObjects:nil];
But I have commented it out. With it our without it the UITableView isn't working.
And of course I have this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.favBookList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"favBooksCell"];
cell.textLabel.text = [self.favBookList
objectAtIndex:indexPath.row];
return cell;
}
No matter what, the UITableView is just empty, no cells, nothing.
What can be the possible mistake here? What am I doing wrong?
Thanks in advance!
Instead of adding the string to the array in the BooksDetailViewController , just pass the string to the FavBooksViewController and then add it to the array in your FavBooksViewController.
- (IBAction)addToFav:(id)sender {
FavBooksViewController *mdvc;
[mdvc setFavBook:myBookString];
//favBook is a NSString member object in your FavBooksViewController class
[self.navigationController pushViewController:mdvc animated:YES];
}
Just try if this works.
You forgot to initiates the cell in your cellForRowAtIndexPath method.
The code should be :
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"favBooksCell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:identifier];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text = [self.favBookList
objectAtIndex:indexPath.row];
return cell;
}
Try this ;-)
Hope this helps.

Create a two tableview list using one TableViewController class

I want to do an sample application where in a view i have two buttons one is COUNTRY and another is STATE.
when i click on a country button the country list should appear in a tableview class like a popup and when i click on state button state list should appear in a tableview like popup,So how can i do this please suggest with sample code.
NOTE:I should use only one TableViewcontroller class for both country and state Data list.
Here is the Code:
RootViewController.h
#interface RootViewController : UIViewController {
UIButton *btnCountry;
UIButton *btnState;
NSMutableArray *tempArray;
NSMutableArray *countryArray;
NSMutableArray *stateArray;
IBOutlet UITableView *tempTable;
}
#property (nonatomic,retain) UIButton *btnCountry;
#property (nonatomic,retain) UIButton *btnState;
#property (nonatomic,retain) NSMutableArray *countryArray;
#property (nonatomic,retain) NSMutableArray *stateArray;
#property (nonatomic,retain) NSMutableArray *tempArray;
#property (nonatomic,retain) UITableView *tempTable;
- (IBAction) showState:(id)sender;
- (IBAction) showCountry:(id)sender;
#end
RootViewController.m
#implementation RootViewController
#synthesize btnState,btnCountry, stateArray,countryArray,tempArray;
#synthesize tempTable;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
tempTable.hidden = YES;
countryArray = [[NSMutableArray alloc]initWithObjects:#"India",#"Pakistan",#"USA",nil];
stateArray = [[NSMutableArray alloc]initWithObjects:#"Gujarat",#"Maharashtra", #"Karnataka",nil];
tempArray = [[NSMutableArray alloc]init];
}
- (IBAction) showCountry:(id)sender
{
btnCountry = (UIButton *)sender;
tempArray = countryArray;
[tempTable reloadData];
if([btnCountry isSelected])
{
tempTable.hidden = YES;
btnCountry.selected = NO;
}
else
{
tempTable.hidden = NO;
btnCountry.selected = YES;
}
}
- (IBAction) showState:(id)sender
{
btnState = (UIButton *)sender;
tempArray = stateArray;
[tempTable reloadData];
if([btnState isSelected])
{
tempTable.hidden = YES;
btnState.selected = NO;
}
else
{
tempTable.hidden = NO;
btnState.selected = YES;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tempArray 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:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [tempArray objectAtIndex:indexPath.row];
return cell;
}
#end
The question is not clear enough ,, what did you try? ..
But, You can use UIPopOverController for that
see
THIS LINK
Or Just a Static UiTableView in the same Nib file ,, make it hidden when you don't need it .
You can use One Tableview for this: Here i am attaching only the logic.
In viewdidload,
There will be two arrays countryArray and stateArray.
There will be a third array : tempArray
there are two buttons: button1 and button2
tableview.hidden=YES;
in button1Action assign the countryArray to tempArray and also [tableview reload]
in button2Action assign the stateArray to tempArray and also [tableview reload]
then in tableview delegates,
(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
return [tempArray count];
}
and then in
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
use tempArray.......
}
try this...and if you want more detailed pls inform....
Take Two tableViews and two Buttons.
Place each tableview below each of the button.
Initially both the TableViews are hidden. When the Button is clicked show the TableView with Animation.
I think you should only use one TableViewController but with different data sources.

Trouble Reloading UITableView

I am trying to create an iphone application that reads a json feed and I am having some trouble updating a TableView.
This is my TableViewController header file:
#interface LiveNewsController : UITableViewController <UITableViewDelegate, UITableViewDataSource>{
NSMutableData *responseData;
NSMutableArray *articleArray;
UITableView *tblView;
}
-(void) refreshPressed: (id)sender;
#property (nonatomic, retain) IBOutlet UITableView *tblView;
#end
These are some parts of my TableViewController implementation file:
#implementation LiveNewsController
#synthesize tblView;
-(id) init {
if(self = [super init])
{
self.title = #"Live News";
}
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"I am here %d",[articleArray count]);
return [articleArray 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:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSLog(#"cellForRowAtIndexPath called. Data size %d", [articleArray count]);
NSUInteger row = [indexPath row];
cell.textLabel.text = [articleArray objectAtIndex:row];
return cell;
}
-(void) refreshPressed: (id)sender
{
NSLog(#"Reload Pressed. Data size: %d", [articleArray count]);
[tblView reloadData];
}
Here is a screenshot of my .xib file with the connections:
So the main idea is the following:
Fetch articleArray
When refresh is pressed update view (the data is being fetched correctly but the snippet doesn't show it here)
numberOfRowsInSection and CellForRowAtIndexPath are only being called once when the view loads but nothing happens when I press the reload button.
I checked tblView and it is nil. I did some research and read that this is usually caused by some erroneous connections in the .xib file but I have triple checked that and I can't seem to pinpoint the problem.
Any help is appreciated,
Thanks!
You don't need to declare the UITableView tblView, the UITableViewController has already one (and therefore all subclasses too).
Just try [self.tableView reloadData];.

How to update numberOfRowsInSection using NSMutableArray count

In my app I allow users to add new rows of NSStrings to a UITableView. I save these new strings in an NSMutableArray *dataArray
So for numberOfRowsInSection I return [dataArray count], but it seems to just return 0 all the time so my table is not auto-populating.
If it helps, when I do an NSLog of [dataArray count] as a add more entries, it keeps remaining as 0. Why isn't it increasing?
Any help?
Without looking # your code ,it's not possible to predict the reason..
Then also you can try your HardLuck...below:
First try to NSLog your dataArray to check wether the record is adding in that or not.
It's its ok... you are getting the records.
then you are missing one thing.
reload the table..
[tableView reloadData];
I think this would definitely help you..otherwise put some code over here.
Have you initialised your Array. Here is how I've done it - prob a better way!
.h:
#interface RootViewController : UITableViewController {
NSArray *array;
}
#property (nonatomic, retain) NSArray *array;
#end
.m:
#implementation RootViewController
#synthesize array;
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *mArry = [[NSMutableArray alloc] init];
[mArry addObject:#"An ObecjT"];
self.array = mArry;
[mArry release];
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array 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:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.text = [array objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableArray *aNewArray = [[NSMutableArray alloc] initWithArray:array];
[aNewArray addObject:#"Your Object"];
self.array = aNewArray;
[aNewArray release];
[self.tableView reloadData];
}
- (void)viewDidUnload {
self.array = nil;
}
- (void)dealloc {
[array release];
[super dealloc];
}
Did you set the delegate for the UITableView in Interface Builder ? please check it.
If you have added, then you have to check with that dataArray whether it is having records or not.

iPhone: UITableView, Dragging Table Contents Causes Crash

I'm new to iPhone application development. I'm trying to understand how to use UITableView.
I'm wrote simple code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1 ;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}
cell.textLabel.text = #"Hello";
return cell;
}
UITable shows content, but if i'm drag table contents my application terminates. You can see video: http://www.youtube.com/watch?v=TucTVJVhSD0
I tried to everything with array:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1 ;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [hello count] ;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}
cell.textLabel.text = [hello objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSLog(#"Selected") ;
}
- (void) awakeFromNib
{
hello = [[NSArray alloc] initWithObjects:#"hello", #"world", #"end", nil];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
Content is shown and if I'm selecting item I'm getting:
[Session started at 2010-03-16 19:21:48 +0200.]
2010-03-16 19:21:52.295 ViewTest[1775:207] *** -[ViewTestViewController respondsToSelector:]: message sent to deallocated instance 0x3911ec0
I'm total new to iPhone programming. And as I see everything I do - I'm just getting application terminated ..
Your table view code looks fine. Did you implement any other delegate methods in the ViewTestViewController?
Try running the application in the debugger. When it crashes, look at the stack trace. It should give a better hint.
(1) I think you may have released your tableview controller instance and killed it while it was still in use so that when the tableview sends it one of its delegate or datasource messages it crashes.
(2) Alternatively, the error message says that you are attempting to send the respondsToSelector: message to an instance of ViewTestViewController when you should be sending it to the class. (-[ViewTestViewController respondsToSelector:] vs + [ViewTestViewController respondsToSelector:] the "-" and "+" make all the difference.)
So, somewhere in your code, probably your app delegate, you've got code that says:
ViewTestViewController *myTableViewController= //..however you setup the controller
[myTableViewController respondsToSelector:#selector(someMethod)];
...when you should have...
[ViewTestViewController respondsToSelector:#selector(someMethod)];
I think (1) the most likely.
Thanks to all. I found problem. I found i haven't connected viewController IBOutlet with App Delegate. But why View was shown ?
#interface ViewTestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ViewTestViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ViewTestViewController *viewController;