I would like to display different content in its corresponding views by using only one subclass for generating a custom table view. When the table view is being filled with data, I would like to send the whole view to a specific view and display it.
When I generate the table view on the displaying view controller there is no problem. Even I can transfer the table view from the displaying view controller to another view, but when I try to generate the table view in another class and try to call it from the the root view controller, I only get a initialised but empty table view.
Here is the code:
tableViewGenerator.h
#import <UIKit/UIKit.h>
#interface TableViewGenerator : UIViewController <UITableViewDataSource, UITableViewDelegate>
- (UITableView *) getTableViewForOtherVC;
#property (nonatomic, strong) IBOutlet UITableView *spreadSheet;
#end
tableViewGenerator.m
...
- (UITableView *) getTableViewForOtherVC {
if (!self.spreadSheet) {
self.spreadSheet = [[UITableView alloc]initWithFrame:CGRectMake(0., 0., self.view.frame.size.width, self.view.frame.size.height/2.5) style:UITableViewStyleGrouped];
}
UITableView *tableViewToBeTransfered = self.spreadSheet;
return tableViewToBeTransfered;
}
...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (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 = #"Test";
return cell;
}
displayingVC.m
#import "DisplayingVC.h"
#import "TableViewGenerator.h"
#interface CTTOVViewController ()
#end
#implementation CTTOVViewController
- (void)viewDidLoad{
[super viewDidLoad];
UITableView *spreadSheet1;
if (!spreadSheet1) {
TableViewGenerator *tableVC = [[TableViewGenerator alloc]init];
spreadSheet1 = [tableVC getTableViewForOtherVC];
[self.view addSubview:spreadSheet1];
}
}
...
#end
I suppose that I have done something wrong on the table filling but I can not find what.
Any hint will be highly appreciated.
Thank you in advance
You don't seem to be setting the table view's dataSource and delegate properties anywhere, so you need to have these properly set.
On a separate front, what you're trying to accomplish is probably much easier if you generate a model, instead of the UITableView itself. I recommend checking out the models provided by free Sensible TableView framework as these can save you a huge amount of time.
Related
I have a TabBarController with 4 tabs, 3 of which are table views. I am trying to put a detail for every table view cell, and I don't think storyboard is efficient since I have over 50 detail pages. I'm very new to all of this, and I've tried to find out how to link a detail to every tab for a couple hours. My table views start with the Second View Controller.
Here is SecondViewController.m:
#import "SecondViewController.h"
#implementation SecondViewController
{
NSArray *tableData;
}
#synthesize tableData;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
tableData = [NSArray arrayWithObjects:#"Carter", #"Greene", #"Hancock", #"Hawkins", #"Johnson", #"Sullivan", #"Unicoi", #"Washington", nil];
[super viewDidLoad];
}
#pragma mark - TableView Data Source methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
#end
Here is SecondViewController.h:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDelegate,
UITableViewDataSource>
#property(nonatomic, retain) NSArray *tableData;
#end
If this helps, here is my storyboard.
If anyone can help me individually add details to each table view cell in the most painless way possible, I would appreciate it. Thanks!
If using storyboards, the process is fairly simple.
First, I'd suggest dragging a prototype "table view cell" on to your table views. You can then control-drag from that prototype cell to your destination scene to add a segue between the cell and the next scene:
Make sure to select that prototype cell and set its storyboard identifier (I used "Cell"). You will need to reference that storyboard identifier, as shown in my code sample below. I also configured appearance related things (like the disclosure indicator) right in that cell prototype in IB so I don't have to worry about doing that in code and I can see what the UI will look like right in IB.
Now you can go to the table view controller and (a) simplify cellForRowAtIndexPath (because you don't need that logic about if (cell == nil) ... when using cell prototypes); but also implement a prepareForSegue to pass the data to the destination scene:
// SecondViewController.m
#import "SecondViewController.h"
#import "DetailsViewController.h"
#interface SecondViewController ()
#property (nonatomic, strong) NSArray *tableData;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableData = #[#"Carter", #"Greene", #"Hancock", #"Hawkins", #"Johnson", #"Sullivan", #"Unicoi", #"Washington"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController isKindOfClass:[DetailsViewController class]]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *name = self.tableData[indexPath.row];
[(DetailsViewController *)segue.destinationViewController setName:name];
}
}
- (IBAction)unwindToTableView:(UIStoryboardSegue *)segue {
// this is intentionally blank; but needed if we want to unwind back here
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.tableData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.tableData[indexPath.row];
return cell;
}
#end
Obviously, this assumes that you created a DetailsViewController and specified it as the destination scene's base class, and then create properties for any values you want to pass to this destination scene:
// DetailsViewController.h
#import <UIKit/UIKit.h>
#interface DetailsViewController : UIViewController
#property (nonatomic, copy) NSString *name;
#end
And this destination scene would then take the name value passed to it and fill in the UILabel:
// DetailsViewController.m
#import "DetailsViewController.h"
#interface DetailsViewController ()
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
#end
#implementation DetailsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.nameLabel.text = self.name;
}
#end
Frankly, this process will undoubtedly be described more clearly in any UITableView tutorial includes a discussion of "cell prototypes" (your code sample suggests you were using an older tutorial that predates cell prototypes).
I think the relationship between the code and the storyboard is as following:
Code implement the function of the application.
Storyboard contains many scenes, these scenes implement the User interface, including data presentation, data input, data output.
Code read data from these scenes and output the result to the scenes.
Code is internal logic function entities and the storyboard the the User Interface presentation.
I try to search this problem in this site and I found this link How to insert items to a UITableView when a UIButton is clicked in iOS. But my problem is, I already copy the code on that link and It doesn't reload the data when I insert a value to my array.
here's the code "ViewController.m"
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic,strong) NSMutableArray * array;
#property(nonatomic,weak) IBOutlet UITableView * tableView;
#end
#implementation ViewController
-(NSMutableArray *) array{
if(_array==nil){
_array=[[NSMutableArray alloc] init];
}
return _array;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)addInfo:(UIBarButtonItem *)sender {
[self.array addObject:#"sample"];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"TodoListItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
return cell;
}
#end
here's the code "ViewController.h"
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#end
Is there something wrong with my code or there is something that I need to setup to my tableview? I'm very confuse of this and try to figure out the missing part of my code. I'm still studying the code of object c and I'm still noob for this. Please help me and thanks in advance.
How did you insert the UITableView?, on nib or programatically?, either way you need to flag the table's delegate and datasource, if on nib, right click on table and see that delegate and data source are connected to the files owner, if programatically check
self.MyTable.datasource = self
self.MyTable.delegate = self
please see how to check if connected [dataSource and delegate should be with a dot, if not click on circle and drag line to file's owner for both]
table delegate and datasource on interface builder "NIB"
Also please note that on this image outlet is not connected, you have to connected also to call the reload as you are doing now
edit, check if the button is connected?, put a log or a break point on ibaction for your button to know if is called
edit 2, you have to init the array, are you calling it? do this in view will appear or when you want to use it
edit 3, try this
- (IBAction)addInfo:(UIBarButtonItem *)sender {
if(self.array==nil){
self.array=[NSMutableArray array];
}
[self.array addObject:#"sample"];
[self.tableView reloadData];
}
I am trying to implement the concept shown in this example project. My goal is to separate my view controller class and the datasource protocol. Instead of implementing the table view datasource methods in my table view controller class, I try to put it in its own class, and in my view controller, I only call this method to set up my table view:
- (void)setupTableView
{
void (^configureCell)(JVRTodoItemCell *, JVRTodoItem *) = ^(JVRTodoItemCell *cell, JVRTodoItem *todoItem)
{
[cell configureForTodoItem:todoItem];
};
NSArray *todoItems = currentUser.todoItems;
self.todoArrayDataSource = [[JVRArrayDataSource alloc] initWithItems:todoItems withCellIdentifier:TodoCellIdentifier withConfigureCellBlock:configureCell];
self.tableView.dataSource = self.todoArrayDataSource;
[self.tableView registerClass:[JVRTodoItemCell class] forCellReuseIdentifier:TodoCellIdentifier];
}
The data source is separated into its own class:
#interface JVRArrayDataSource ()
#property (copy,nonatomic) NSArray *items;
#property (copy,nonatomic) NSString *cellIdentifier;
#property (copy,nonatomic) void (^configureCellBlock)(id item, id cell);
#end
#implementation JVRArrayDataSource
...
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
self.configureCellBlock(cell,item);
return cell;
}
The interesting part is that creating the cell based on the identifier (using dequeueReusableCellWithIdentifier:forIndexPath:) seems to be successful, because the correct cell gets allocated, but its labels remain nil. I try setting up my cell using the following method, but the values remain nil (aTodoItem has valid properties):
- (void)configureForTodoItem:(JVRTodoItem *)aTodoItem
{
self.todoItemTitle.text = aTodoItem.title;
self.todoItemPriority.text = [NSString stringWithFormat:#"%d", aTodoItem.priority];
}
I am trying to figure out what could possibly be missing here, but so far, I haven't managed to fix the issue yet, and I'm starting to lose hope. Any help would be appreciated.
UPDATE:
To make it clear, the issue is shown on this picture.
It seems that the cells get created, but its labels don't.
If all you want to do is separate your tableview datasource delegate from the view controller you can create a separate class called TableViewDataSource. Within that class you can manage the datasources and their table view cells; configuring the them in your view controller, but letting the TableViewDataSource manage them.
TDSTableViewDataSource.h
#import <Foundation/Foundation.h>
#protocol TDSTableViewDataSourceDelegate <NSObject>
- (NSString *)fetchCellIdentifierForObject:(id)object;
- (UITableViewCell *)configureCell:(UITableViewCell *)cell usingObject:(id)item;
#end
#interface TDSTableViewDataSource : NSObject <UITableViewDataSource>
#property (strong, nonatomic) NSArray *items;
#property (strong, nonatomic) id<TDSTableViewDataSourceDelegate> delegate;
#end
TableViewDataSource.m
#import "TDSTableViewDataSource.h"
#implementation TDSTableViewDataSource
- (NSArray *)items {
if (!_items) _items = [[NSArray alloc] init];
return _items;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if ([self.items count]) {
return [self.items count];
} else {
NSLog(#"numberOfSectionsInTableView could not be determined. self.items is nil or empty.");
return 0;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([self.items count]) {
return [self.items count];
} else {
NSLog(#"numberOfRowsInSection could not be determined. self.items contains fewer section requested does not contain any items.");
return 0;
}
}
/*
Single dimension Array of items belonging to a UITableView section
The method checks if the cell implements the HZConfigureTableViewCellDelegate, which is required.
The delegate should be the View Controller.
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id obj = [self.items objectAtIndex:indexPath.row];
UITableViewCell *cell = nil;
if ([self.delegate conformsToProtocol:#protocol(TDSTableViewDataSourceDelegate)]) {
NSString *cellIdentifier = [self.delegate fetchCellIdentifierForObject:obj];
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (obj)
cell = [self.delegate configureCell:cell usingObject:obj];
}
return cell;
}
#end
This class and the protocol will essentially allow you to fetch and configure UITableViewCell's and not have to implement the protocols into your View Controller.
Inside your view controller, you create a datasource property using the protocol above.
#import "TDSViewController.h"
#import "TDSTableViewDataSource.h"
#interface TDSViewController () <UITableViewDelegate, TDSTableViewDataSourceDelegate>
#property (strong, nonatomic) TDSTableViewDataSource *dataSource; // UITableView data source.
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation TDSViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self.dataSource;
self.dataSource.delegate = self;
}
#pragma mark - UITableView methods
-(NSString *)fetchCellIdentifierForObject:(id)object {
// Check if this is an event or a Reminder class.
if ([object isKindOfClass:[UITableViewCell class]]) {
// Return the cell identifier for this particular cell.
return #"com.myapp.defaultcell";
}
return #"blankcell";
}
- (UITableViewCell *)configureCell:(UITableViewCell *)cell usingObject:(id)item {
UITableViewCell *configuredCell = cell;
// Check if this is an event or a reminder.
if ([item isKindOfClass:[UITableViewCell class]]) {
// Configure the cell to present what data we want here...
}
return configuredCell;
}
#end
This is a complete example project. You can use this to configure any kind of cell you want, without having to add the datasource methods to your view controllers.
The view controller is used by the ConfigureTableViewCellDelegate protocol to configure the UITableViewCell's and use them in the Table View. Since the code is segregated now, the TableViewDataSource class now handles presenting the data to the table view. The View Controller is simply used to configure the cell's. This allows you to use custom UITableViewCells' on each ViewController if you want, and not have to deal with implementing the data sources each time.
UPDATED
Provided a better example, a complete project template.
In the ViewDidLoad register the nib, it fix the problem :)
-(void)viewDidLoad
{
[self.leftTableView registerNib:[UINib nibWithNibName:NIB_FILE bundle:nil] forCellReuseIdentifier:CELL_IDENTIFIER];
}
After hours of digging, I've managed to solve the issue (for now), by changing my custom cell's outlets to strong properties, and initializing them in the cell's init method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.todoItemTitle = [[UILabel alloc] init];
self.todoItemPriority = [[UILabel alloc] init];
}
return self;
}
This is very strange, since I thought that creating my views in storyboard, this should be automatically taken care of, and I've never had to do this manually before.
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.
I'm a newbie programming iOS and I've a problem adding a new cell to a UITableView object. I'm using an storyboard and one of the scenes is a UIViewController that has several subviews: textfields, a tableview, etc. I intend to add rows to this tableView from a detail scene.
I'm able to initially add rows to the table, but I'm not able to add a row afterwards. When I press a button to add the row I call the method '[self.stepsListTableView reloadData];' which produces a call to the method '- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section' and it returns a correct value, including the new array element. But method '- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath' is not called to update the table.
I do not understand what I'm doing wrong.
Details of my source code:
WorkoutDetailsViewController.h
(…)
#interface WorkoutDetailsViewController : UIViewController <StepDetailsViewControllerDelegate, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) id <WorkoutDetailsViewControllerDelegate> delegate;
#property (nonatomic, strong) Workout *workout;
(…)
#property (nonatomic, retain) IBOutlet UITableView *stepsListTableView;
(…)
WorkoutDetailsViewController.m
(…)
#synthesize stepsListTableView;
(…)
- (void)viewDidLoad
{
[super viewDidLoad];
addButton.enabled = FALSE;
workoutNameField.delegate = self;
if (self.workout == nil) {
self.workout = [[Workout alloc] init];
self.stepsListTableView = [[UITableView alloc] init];
}
self.stepsListTableView.delegate = self;
self.stepsListTableView.dataSource = self;
}
(…)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return [self.workout.stepsList count];
NSInteger counter = 0;
counter = [self.workout.stepsList count];
return counter;
}
// 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];
}
// Set up the cell...
// Pending
return cell;
}
- (void)stepDetailsViewControllerDidDone:(StepDetailsViewController *)controller
{
[self.workout.stepsList addObject:controller.step];
NSInteger counter = [self.workout.stepsList count];
[self.stepsListTableView beginUpdates];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:(counter-1) inSection:0]];
[self.stepsListTableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[self.stepsListTableView endUpdates];
[self.stepsListTableView reloadData];
}
(…)
Also in the storyboard, I have setup the outlets delegate and dataSource to be the controller view.
Any idea ?
Regards,
JoanBa
I have solved the issue. I have discovered using debugger that method reloadData was called for a different UITableView than the one initialized in viewDidLoad.
I reviewed the UITableView settings in storyboard, which aparently were correct but I have deleted them and created again. Now it works.
In UIViewController header I have the line
#property (nonatomic, retain) IBOutlet UITableView *stepsListTableView;
and in implementation I have commented lines
//self.stepsListTableView.delegate = self;
//self.stepsListTableView.dataSource = self;
And, of course, in storyboard I have defined for the UITableView the following relationships:
Outlets: dataSource, delegate --> UIViewController
Referencing outlet: UITableView --> UIVIewController
That's it !!
You may have the table view set to static content. Select the UITableView in Storyboard and in the "Attributes Inspector" section of the menu on the right of screen select the "Content" field under the "Table View" header and set the value to "Dynamic Prototypes".
Screenshot for clarity:
This little trick caught me out several times when I was starting out.