I'm doing something similar to the person's code in how to set a tableview delegate. However, one difference is I created a nib with a UITableView (along with other UIView elements), and I set the nib's File Owner to my custom class, which is defined as
#interface MyCustomView : UIViewConroller <UITableViewDelegate, UITableViewDataSource>
#end
In the nib, I set the Table View object's delegate and dataSource to the File Owner. When I load my view, I don't even hit the code for
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
What else am I missing?
lootsch gave me the clue. I do indeed do this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_myObjArray count];
}
But I was setting populating the array in the wrong place, so it was returning a count of 0. Hence I don't see the data!
Related
Posting a specific question/answer to a specific problem (unlike the general problems with this method I've seen elsewhere):
I have a UITableView, which is a part of a custom UITableViewController, which I setup and then add to a different view controller.
My UITableView is being loaded, calls all the appropriate setup methods (e.g. numberOfRowsInSection, numberOfSectionsInTableView, etc), but cellForRowAtIndexPath is never called.
I've confirmed that the dataset is being loaded - numberOfRowsInSection is not always zero.
What gives??
The goal appears to be the reuse of a table view's datasource. This can be accomplished by separating the datasource from the view controller. In outline, as follows:
// MyTableViewDatasource.h
#interface MyTableViewDatasource : NSObject <UITableViewDatasource>
#property(strong,nonatomic) NSMutableArray *array;
#end
// MyTableViewDatasource.m
#import "MyTableViewDatasource.h"
#implementation MyTableViewDatasource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)s {
return self.array.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// your cell config logic from the original view controller
// replace any mention of that vc's model array with self.array
}
#end
Now, say ViewControllerA has a tableView, and we want its datasource to be our newly defined datasource...
// ViewControllerA.m
#import "ViewControllerA.h"
#import "MyTableViewDatasource.h"
#interface ViewControllerA ()
#property(strong,nonatomic) MyTableViewDatasource *datasource;
#end
-(void)viewDidLoad {
// create our data and our datasource
// don't have to do this in viewDidLoad, but it needs to be done
// before the table can be seen, anytime after the model is ready
// this "model" in your case is whatever array that holds the data for the table
NSMutableArray *model = [#[#"Moe", #"Larry", #"Curly"] mutableCopy];
MyTableViewDatasource *datasource = [[MyTableViewDatasource alloc] init];
datasource.array = model;
self.tableView.datasource = datasource;
}
Now ViewControllerA, wherever it once modified its model array, should do the same this way...
[self.datasource.array addObject:#"Shemp"];
[self.tableView reloadData];
Hopefully it's clear that ViewControllerB and C and so on can do the same thing, replacing the code that you posted in your answer.
If you are using ARC, then it's very likely that your custom view controller, which is the ultimate owner of your UITableView, it being trashed as soon as you add the tableView to another view.
Try adding the UITableView's view controller to the master/other view controller's, either via a property or through the view hierarchy.
In my case, I simply created a new property for it in the view controller that wanted its table:
#property (strong, nonatomic) MyTableViewController *tvc;
and later assigned it to self when creating it:
self.tvc = [[MyTableViewController alloc] init];
[self.someOtherView addSubview:tvc.tableView];
My table view is inside a UI View, this has been done writing codes, now i am trying to reload the data in table view but the table view is not refreshing.
The UIview and the table view declaration are as follows:
#interface
{
IBOutlet UITableView *tabView;
}
#property (nonatomic, strong) IBOutlet * tabView
#property (nonatomic, strong) UIView * myView; // in .m file
Ok there could be various mistakes which lead to your problem. First of all do you implement the datasource and delegate methods ?
To do so you should declare your header like this:
#interface MyClass : UIViewController<UITableViewDelegate, UITableViewDataSource> {}
Second you should hook up your tableView with those delegate/datasource methods. To do so drag&drop it in the InterfaceBuilder or in you viewDidLoad method write this:
tableView.delegate = self;
tableView.dataSource = self;
Now make sure to implement all the necessary methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {}
If you done all this you should update your tableView like so:
[tableView reloadData];
Also check if you connected your IBOutlet UITableView *tableView; in the Interface Builder.
Provided you have linked up the delegate and the data source methods of the table view correctly, you could just do :
[self.tableView reloadData];
Make sure you have done :
self.tableView.dataSource = self;
I have drag the tableview into a view controller.
i have created an outlet property to the table .
#property (strong, nonatomic) IBOutlet UITableView *tableView;
i have added the delegate in the interface
UITableViewDelegate
4.registered the delegate with :
tableView.delegate=self;
and added all functions of a tableview, that usually did worked before :
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
And all the others.
the functions are not being called at start.
What am i missing here ?
You are missing the tableView's dataSource. These methods appear on the dataSource, not the delegate.
Set tableView.dataSource=self; as well, and you should be good to go.
UITableView has two delegates delegate and dataSource as they handle different areas of focus.
You may be missing one of the following things.
1.Make sure you have set your datasource and delegate of your TableView as your current view controller by Xibs or by code.
2.Do mention your protocal that you have to implement in header of your like below.
#interface ViewController()<UITableViewDataSource,UITableViewDelegate>
How do I add a UITableView to an existing view?
I have added the control via interface builder, and added the correct delegates to the host view controller (including adding the table cell functions to the .m file)
But nothing gets called and nothing gets populated, the cellForRowAtIndexPath function, for example, never gets called.
in .h file
#interface GameViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *friendsScoresView;
in .m file
init {
_friendsScoresView.delegate = self;
_friendsScoresView.dataSource = self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// return number of rows
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyBasicCell"];
//NSMutableArray *nearbyScores = gclb->nearbyScores;
GCLeaderboardScore *playerScore = [gclb->nearbyScores objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%f",playerScore->score ];
cell.imageView.image = playerScore->photo;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// handle table view selection
}
What am I missing? Also how do I tell the table to update / refresh its contents?
If you added the UITableViewController in IB then click on the outlets tab on the right and connect the DataSource and Delegate in IB. If you want to do it in code, then create an IBOutlet variable for your table and set the delegate and datasource property on your variable. Also, you can't do it on init on the UIViewController as the NIB has not yet been loaded. Do it on viewDidLoad.
I have a class like this:
#interface ExerciseLogDetails : UIViewController<UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
where I am trying to display some elements followed by a UITextView. The UITextView element is created on Interface Builder. When executing this code:
- (void)viewDidLoad {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:self.tableView];
}
a table shows, but not the one I configured in Interface Builder. It is completely blank and unformatted. How can I access my table and populate it progrmmatically with data?
Thank you!
Several of the tips on this thread helped me create this. I am going to offer some more complete code files in order to help others as well:
Step 1. Drag your UITableView onto your View Controller either in Storyboards or XIBs. In my example I am using a story board.
Step 2: Open your ViewController (in my case its just DefaultViewController) and add the two delegates for the UITableView: UITableViewDelegate and UITableViewDataSource. Also add a simple data source for population and the UITableView IBOutlet.
DefaultViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSMutableArray *newsArray;
#end
Step 3: Open your implementation file (DefaultViewController.m) and add the following:
#import "DetailViewController.h"
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#synthesize newsArray;
#synthesize tableView;
#pragma mark - Managing the detail item
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)configureView
{
// Update the user interface for the detail item.
self.newsArray = [[NSMutableArray alloc] initWithObjects:#"Hello World",#"Goodbye World", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// typically you need know which item the user has selected.
// this method allows you to keep track of the selection
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
// This will tell your UITableView how many rows you wish to have in each section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.newsArray count];
}
// This will tell your UITableView what data to put in which cells in your table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifer = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
}
// Deciding which data to put into this particular cell.
// If it the first row, the data input will be "Data1" from the array.
NSUInteger row = [indexPath row];
cell.textLabel.text = [self.newsArray objectAtIndex:row];
return cell;
}
#end
Step 4: Goto your Storyboards or XIB and select your UITableView and drag the datasource and delegate outlets onto your DefaultViewController to wire them up. Also you will need to wire up the Referencing Outlet for the UITableView to your IBOutlet tableView object you created in your header file.
Once this is finished you should be able to run it and the sample data will be in place.
I hope this along with the other tips on this thread will help others setup a UITableView from scratch on a ViewController.
If you configured a tableView in IB you shouldn't also create one programmatically, you should create #property (nonatomic, retain) IBOutlet UITableView *tableView; and connect it to the tableView you configured in IB.
Try to set a breakpoint in the tableView's
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
delegate method to see if this method get called.
From Apple UITableView docs:
A UITableView object must have an object that acts as a data source
and an object that acts as a delegate; typically these objects are
either the application delegate or, more frequently, a custom
UITableViewController object. The data source must adopt the
UITableViewDataSource protocol and the delegate must adopt the
UITableViewDelegate protocol. The data source provides information
that UITableView needs to construct tables and manages the data model
when rows of a table are inserted, deleted, or reordered. The delegate
provides the cells used by tables and performs other tasks, such as
managing accessory views and selections.
As u can see if u don't set a dataSource to your tableView, the tableView will not know how and what to display, so nothing will happen.
You can set one by calling tableView.dataSource = self; or in IB drag from your tableView to the file's owner (that is your viewController that must implement the UITableViewDataSource Protocol)
There are two methods in the UITableViewDataSource protocol that your dataSource must implement:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
and
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
If u won't implement those methods u will get a compiler warnings.
You can have more control on how the tableView will look if you implement the UITableViewDelegate protocol - like row/header/footer height, selections and more...
From Apple UITableView docs:
UITableView overrides the layoutSubviews method of UIView so that it
calls reloadData only when you create a new instance of UITableView or
when you assign a new data source. Reloading the table view clears
current state, including the current selection. However, if you
explicitly call reloadData, it clears this state and any subsequent
direct or indirect call to layoutSubviews does not trigger a reload.
ReloadData get called when the tableView is created or when you assign a new dataSource (or when you explicitly call it of course..).
This is when the tableView needs to know what to display (how many sections?, how many rows?, and which cell to display?) - So this is when numberOfRowsInSextion method called.
Like Eyal said, you shouldn't create a UITableView programmatically and in the Interface Builder. Instead, it is much easier to just create one in Interface Builder and assigns it's delegate and datasource properties to File's Owner in IB.
Once you've done this, you don't need to create one programmatically and there's no need for a #property for the tableview.
Instead, you could have your UIViewController's class files look like this:
// YourViewController.h
#import <UIKit/UIKit.h>
#interface YourViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (strong, nonatomic) NSArray *yourData;
#end
Where the NSArray will contain your data that you will enter into the table programmatically. You may use other data classes too like an NSDictionary depending on what data you have and how you want it to sit in the table.
// YourViewController.m
#import "YourViewController.h"
#implementation YourViewController
#synthesize yourData;
- (void)viewDidLoad
{
[super viewDidLoad];
// Here you are creating some data to go in your table by inputting it as an array.
// I just used some basic strings as an example.
NSArray *array = [[NSArray alloc] initWithObjects:#"Data1", #"Data2", #"Data3", nil];
// Copying the array you just created to your data array for use in your table.
self.yourData = array;
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.yourData = nil;
}
#pragma mark Table View Data Source Methods
// This will tell your UITableView how many rows you wish to have in each section.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.yourData count];
}
// This will tell your UITableView what data to put in which cells in your table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifer = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
}
// Deciding which data to put into this particular cell.
// If it the first row, the data input will be "Data1" from the array.
NSUInteger row = [indexPath row];
cell.textLabel.text = [yourData objectAtIndex:row];
return cell;
}
#end
This should just create a simple UITableView with three entries of data that you have entered programmatically.
If you have any problems or questions just post a comment. :)
Hope this helps.