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.
Related
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];
}
I have a table and I want to show there some text; but I can't, I don't know why. My app is a view-based app, and I don't want to change it for a Table View Controller. Here's the code:
.h
{
NSArray *array;
IBOutlet UITableView *table;
}
.m
- (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 [array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [array objectAtIndex:indexPath.row];
// Configure the cell
return cell;
}
Please help me because I'm trying to solve this and I don't know what's wrong, why the Table doesn't show the array!
Thank you!
You almost certainly haven't connected your datasource and delegates properly in IB.
Your UIViewController needs to implement UITableViewDelegate and UITableViewDatasource, and you need to then connect it to your UITableView (table) as such in Interface Builder.
For details, read through Apple's documentation here.
On your .H file are you using this interfaces <UITableViewDelegate, UITableViewDataSource>?
The answer is that you've never ever created single cell. The call you make dequeueReusableCellWithIndentifier only recycles cells you've already created. Add this code after the dequeueResusable... line:
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
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];.
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.
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;