Choose objects inside UITableView chosen by UIPickerView - ios

This is a very broad question, not a specific question about a single problem. If you don't want to help with one of these, here is your warning!
I have a View with a pickerWheel. On this picker, I want to have a list of Cargo ship owners. When I press an OK Button, I want a UITableView to be populated by the boats this owner has. Not many, about 5 ships. I want the tableView to be on the same view as the picker.
When I press a ship in the list, I want to be directed into another view where I can add variable numbers from another view, like carriage load etc.
I know how to make and populate and extract data from the picker, and I DO NOT KNOW how to use this data to somehow populate a table and i do not know how to use a object on a table to link me to a view where i can set different values depending on who sent it.
I am bad at programming, so fullout solutions with code would be great!:)
EDIT: Code i have so far
.h file
#import <UIKit/UIKit.h>
#import "StartupViewController.h"
#interface CargoViewController : UIViewController
#property(strong,nonatomic) IBOutlet UILabel *testLabel; //label I use to test stuff instead of LOG
#property(strong,nonatomic) IBOutlet UIButton *findOwner; //button to summon pickerWheel
#property(strong,nonatomic) IBOutlet UIButton *findShip; //Button to confirm selection in picker and unhide tableView
#property(strong,nonatomic) NSArray *boatOwners; //Array for boat owners.
#property(strong,nonatomic) NSMutableArray *boatsForOwner; //My idea was that when you select a owner, i have a if-else series, so say i select "Bob", I code to add his boats to the array. Does this work? IDK
#property(strong,nonatomic) IBOutlet UITableView *boatsTableView; //Table view
-(IBAction)findOwnerButtonPressed:(id)sender;
-(IBAction)findShipButtonPressed:(id)sender;
#property(strong, nonatomic) IBOutlet UIPickerView *shipOwners; //ship owner picker wheel
#end
.m file:
#import "CargoViewController.h"
#interface CargoViewController ()
#end
#implementation CargoViewController
#synthesize testLabel, findOwner, findShip,shipOwners, boatsTableView;
#synthesize boatsForOwner, boatOwners;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[self getDataFromDensity ];
boatOwners = #[#"owner1", #"owner2", #"owner3"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) getDataFromDensity
{
NSString *getData = [[NSUserDefaults standardUserDefaults]
objectForKey:#"globalMathString"]; //Gets a number from another view, wanted to use in the information about boat view later on.
testLabel.text = getData;
[boatsForOwner setValue:#"5" forKey:getData];
}
-(IBAction)findOwnerButtonPressed:(id)sender
{
findShip.hidden = NO;
shipOwners.hidden = NO;
boatsTableView.hidden = YES;
}
-(IBAction)findShipButtonPressed:(id)sender
{
shipOwners.hidden = YES;
findShip.hidden = YES;
boatsTableView.hidden = NO;
}
#pragma mark -
#pragma mark PickerView DataSource
- (NSInteger)numberOfComponentsInPickerView:
(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return [boatOwners count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return [boatOwners objectAtIndex:row];
}
#pragma mark -
#pragma mark PickerView Delegate
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
NSString *boatsFromOwner = [boatOwners objectAtIndex:[shipOwners selectedRowInComponent:0]];
}

In pseudothinking i think you'll need something like this.
cargoshipOwner.h // Class that holds all details for a cargoship owner.
The class probably has a property
NSMutableArray *listOfCurrentlyOwnedShips;
Which is filled with:
cargoShip.h // CargoShip class.
NSInteger carriageLoad;
UIColor *shipColor;
NSString *model;
NSString *name;
It sounds like you want to populate your pickerview with a NSMutableArray filled with cargoshipOwners and when one is selected you want to pass the
object's property listOfCurrentlyOwnedShips and populate the UITableView
When you've got that running you can easily push to a detailView with the cargoship object and manipulate it.
Once you have set up your UITableViewDelegate and it's functions properly you should have the following functions in your .m file.
You'll need to use the function cellForRowAtIndexPath: to draw your cells, an example could look like this:
-(UItableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexpath
{
// Create a cell with 300 width and 80 height.
UITableViewCell *cell = [[UITableViewCell alloc] initWithFrame:CGRectmake(0,0,300,80)];
// Create a label.
UILabel *lblCargoShipOwner = [[UILabel alloc] initWithFrame:CGRectMake(10,12,200,20)];
lblCargoShipOwner.tag = 1;
lblCargoShipOwner.textColor = [UIColor blackColor];
lblCargoShipOwner.backGroundColor = [UIColor clearColor];
// Add it to your cell.
[cell.contentView addSubView:lblCargoShipOwner];
// Get the label.
UILabel *textLabel = (UILabel *)[cell viewWithtag:1];
// Add the owner's name to the label.
textLabel.text = [[listOfCargoShipOwners objectAtIndex:indexPath.row]sName];
// important to note is that listOfCargoShipOwners is your datasource.
}
When you've populated your UITableView you can tap a cell and specify what happens within tableView:didSelectRowAtIndexPath: An example:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexpath *)indexPath
{
// Push the owner's list of ships to a UITableViewController
DetailViewController *dvc = [[DetailViewController alloc] initWithStyle:UITableViewStylePlain andCargoShipList: [[listOfCargoShipOwners objectAtindex:indexPath.row]listOfCurrentlyOwnedShips]];
}
DISCLAIMER: This was written without any form of IDE so it may or may not compile at all. This is also just an example, the code itself may or may not be optimized for your specific problem.

Two hints:
1. If you implement the UITableViewDelegate protocol, then you will be notified when the user selects a row in the table view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
So you can change the contents of the view accordingly, and then push that view in your UINavigationController.
2. Check the UITableViewDataSource protocol to know how to put the contents inside the table view.

Related

reload data in UITABLEVIEW object c when clicking button

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];
}

Table view cell properties remain nil

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.

Save selected row in Table View and get back to main screen UIButtons [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
Plz code Help Can anyone tell me how to do that task?
In main screen user selects footballer,in 2nd screen in Table view cell user select specific row and save that row and go back to main view.in main view then it shows the specific row videos.
Basically i want to know about speific row selection,save that selection in table view and show thier contetnts in main screen.
go through the below code, it implements the delegate concept and also implements the solution for ur question hope this helps u :)
//in your main view controller
#import "ViewController.h"
#import "FootBallPlayersViewController.h"
#interface ViewController ()<FootballPlayerDelegate>//confirms to this delegate
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)whenSelectButtonClicked:(id)sender
{
FootBallPlayersViewController *controller = [[FootBallPlayersViewController alloc]initWithNibName:#"FootBallPlayersViewController" bundle:nil];
controller.delegate = self; //u must set to self
[self presentViewController:controller animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)selectedFootBallPlayer:(NSString *)player
{
//implementation of your delegate method
//hear u are getting the football player name and u can continue further hear
NSLog(#"%#",player);
if([player isEqualToString:#"player1"])
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTitle:player forState:UIControlStateNormal];
[aButton addTarget:self action:#selector(whenFirstPlayerButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; //add the target to self for click events
aButton.frame = CGRectMake(50, 50, 200, 55);
[self.view addSubview:aButton];
}
else
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTitle:player forState:UIControlStateNormal];
aButton.frame = CGRectMake(50, 105, 200, 55);
[aButton addTarget:self action:#selector(whenSecondPlayerButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; //same hear
[self.view addSubview:aButton];
}
}
//now define the action methods
- (void)whenFirstPlayerButtonClicked:(UIButton *)sender
{
NSLog(#"player 1 video start");
}
- (void)whenSecondPlayerButtonClicked:(UIButton *)sender
{
NSLog(#"player 2 video start ");
}
#end
in the view that contain's the tableview do somthing like this
//in FootBallPlayersViewController.h
#import <UIKit/UIKit.h>
#protocol FootballPlayerDelegate <NSObject> //define a protocol named FootballPlayerDelegate
- (void)selectedFootBallPlayer:(NSString *)player;
#end
#interface FootBallPlayersViewController : UIViewController
{
NSArray *players;
NSString *selectedPlayer;
}
#property (retain, nonatomic) IBOutlet UITableView *playerTable;
#property (nonatomic, assign) id<FootballPlayerDelegate>delegate; //create a delegate
#end
in your FootBallPlayersViewController.m file
#import "FootBallPlayersViewController.h"
#interface FootBallPlayersViewController ()<UITableViewDataSource,UITableViewDelegate>
{
}
#end
#implementation FootBallPlayersViewController
#synthesize delegate; //synthesizing the delegate
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
players = [[NSArray alloc]initWithObjects:#"player1",#"player2", nil];
// players = [[NSArray alloc]initWithObjects:#"player1","player2", nil];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc
{
[players release];
[_playerTable release];
[super dealloc];
}
- (IBAction)whenDoneButtonClicked:(id)sender {
//when done button clicked -->
//send a delegate to main controller
if([self.delegate respondsToSelector:#selector(selectedFootBallPlayer:)])//to avoid crash
{
[self.delegate selectedFootBallPlayer:selectedPlayer]; //call the delegate method hear
}
//dismiss the view
[self dismissViewControllerAnimated:YES completion:nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return players.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [players objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//u can manage check mark and all, i am getting the selected player name
selectedPlayer = [players objectAtIndex:indexPath.row];
}
#end
Simple solution ...
As you are a newbie , I am clarifying each point.
First make a property in AppDelegate.h
#property int selectedRow;
Save the selected indexpath.row in 2nd screen that is your Table view screen, and also import AppDelegate.h
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.appDelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate];
self.appDelegate.selectedRow=indexPath.row; //saving the row
}
On main screen's viewWillAppear()
-(void)viewWillAppear:(BOOL)animated
{
if(self.appDelegate.selectedRow!=-1)//check wether row is selected or not
{
//action to show the specific row videos
}
}
Good Ways to accomplish this:
Custom Delegate
NSNotificationCenter
NSUserDefaults (edit: unnecessary disk writes)
Maintaining a Common NSObject Subclass and refreshing data on -willAppear
Other Ways:
Database (Core Data / SQLite) or plist (all too heavy for your case) (edit: unnecessary disk writes)
UIPasteBoard
A quick delegate tutorial:
Part 1: Creating the delegate
Suppose this is in the .h of the UITableViewController subclass that I have named YourTableViewControllerClassName
//declare the protocol
#class YourTableViewControllerClassName;
#protocol YourTableViewControllerClassNameDelegate <NSObject>
//#required //uncomment to specify required delegate methods as below
//- (void)requiredMethodNotUsedForThisExample;
#optional
- (void)selectedRow: (NSString *)selectedObj;
#end
#interface YourTableViewControllerClassName : UITableViewController
//declare a weak property to store any object
#property (nonatomic, weak) id <YourTableViewControllerClassNameDelegate> delegate;
#end
Suppose this is the -didSelectRowAtIndexPath of the corresponding UITableViewController subclass:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//the following line is the main thing and can be called
//in any method within this class (placed wisely)
if([[self delegate] respondsToSelector:#selector(selectedRow)]) { //avoid crash
[[self delegate] selectedRow:cell.textLabel.text];
}
[self.navigationController popViewControllerAnimated:YES];
}
Part 2: Implementing the delegate
Suppose this is the code somewhere in the former UIViewController subclass:
//call this method somewhere
-(void)pushMyTableViewController
{
//declare "UILabel lblText;" in the .h of this class
//lblText = [UILabel alloc] init];
//[lblText setFrame: CGRectMake(0,0,100,35)];
//[self.view addSubview:lblText];
YourTableViewControllerClassName *tvcObj = [[YourTableViewControllerClassName alloc] init];
//for the following line, remember to declare
//<YourTableViewControllerClassNameDelegate> in the .h of this class
//hence declaring that this class conforms to the delegate protocol
[tvcObj setDelegate:self];
[self.navigationController pushViewController:tvcObj animated:YES];
}
And this will be the delegate method you could implement in the former UIViewController subclass:
#pragma mark - Optional YourTableViewControllerClassName Delegate Methods
-(void)selectedRow:(NSString *)selectedObj
{
[lblText setText:selectedObj];
}
NOTE: This will not solve your particular issue because we are only setting a label depending on the selected row from the UITableViewController subclass.
The point was to show how delegation works.
Also, if you can get the cell.textLabel.text and set it on a UILabel in the former class then you can make changes at the appropriate places (mainly the method/s within #protocol)and pass the array index of the selected item instead or any object/variable/whatever that makes your life easier
*If you want something easier then go for NSNotificationCenter or NSUserDefaults or maybe even UIPasteBoard (if it floats your boat)
Use the tableView delegate called when you select any row
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
appDelegate.selectedindex = indexpath.row;
or
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:indexpath.row] forKey:#"SelcetedIndex"];
}
then there is 3 things you can do to get your selected index
1) make a app delegate variable for index path so that you can set here and get the value on other controller
// add property at appDelegate file
#property int selectedIndex;
2) Using NSUserDefault to set the selected index value
// read userDefault value
[[[NSUserDefaults standardUserDefaults] objectForKey:#"SelcetedIndex"] intValue];
3) using delegate to return back the value to previous controller
// try to google and first understand the concept and let me know if you want to go with delgate

TableView within ViewController not displaying cells

I'm fairly new to iOS development and I've been wrestling with a solution for this for about a day now and can't figure out why it is not working. I am trying to use a tableview within a viewcontroller as a small menu for the user to use. I have checked to see if the NSArray is being populated, and it is. I have also checked to see if the cell is being created, and it is. I just can't figure why it is not populating the tableview with the cells it creates. Below is my the code that I have so far. Thanks in advance for any help anyone can provide.
MainViewController.h
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *menuTableView;
#property (weak, nonatomic) IBOutlet UIButton *menuButton;
#property (strong, nonatomic) NSArray *menuItemsArray;
#property (weak, nonatomic) IBOutlet UILabel *menuLabel;
#end
MainViewController.m
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize menuItemsArray, menuTableView, menuButton, menuLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Set TableView Delegate/DataSource to self
[self.menuTableView setDelegate:self];
[self.menuTableView setDataSource:self];
[self.menuTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
[self.menuTableView setBounces:NO];
[self.menuTableView setRowHeight:self.menuLabel.frame.size.height];
self.menuItemsArray = [[NSArray alloc] initWithObjects:#"Add Category", #"Add Item", #"Settings", nil];
NSLog(#"array: %#", menuItemsArray);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - UITableViewDelegate
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return ([self.menuItemsArray count]);
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"menuCell"];
[[cell textLabel]setText:[self.menuItemsArray objectAtIndex:indexPath.row]];
[[cell textLabel]setFont:[self.menuLabel font]];
return cell;
}
-(void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self.menuTableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *selectedString = [self.menuItemsArray objectAtIndex:indexPath.row];
self.menuLabel.text = selectedString;
}
I had the same problem, my table view was not getting displayed within a view controller.
I have found a solution.
You can create another view controller with a Container view on it. And put ur table view on a Table View controller. just embed the table view controller to the container view of ur mail view controller.
Make sure your initWithNib method is being called. If you are calling [[MainController alloc] init] your "menuTableView" will never be created from the Nib. Also, double-check the table view by setting the backgroundColor of the main table view to [UIColor red] or something just to make sure the tableView is present and that it has the frame you expect. It might be sitting behind one of your other views, have a frame of (0,0,0,0), or not be present in the view at all.
Also try calling [self.menuTableView reloadData] at the end of your 'viewDidLoad' or initialize the menuItemsArray before you set the data source and delegate (i.e. in your initWithNib method).
And when you do get it all working (you are very close) you will want to change your cellForRow method to something more like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:#"menuCell"];
if(!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"menuCell"];
}
[[cell textLabel]setText:[self.menuItemsArray objectAtIndex:indexPath.row]];
[[cell textLabel]setFont:[self.menuLabel font]];
return cell;
}
This will allow you to take advantage of the cell reuse that makes table views so efficient.
This is a bit late as you have found a way around it but I was having the same problem as you and found that I needed to connect the IBOutlet property to the table view in storyboard and then it all worked.
I hope this helps you in future.
One cause of the symptoms described is if you have placed the UITableView in the parent view using a container view in a storyboard, but are initialising and populating in code a different instance of the UITableView than the one that is actually being presented to the user. If you have placed the UITableView within the view using a container view, then you need to do the following:
Connect the UITableView to the container view with a segue, by Control-Dragging from the container view to the UITableView in the Storyboard.
Click on the segue, and give it a name e.g. tableViewSegue.
Set up the table by implementing prepareForSegue:sender:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueName = segue.identifier;
if ([segueName isEqualToString: #"tableViewSegue"]) {
UIViewController * myTableView = [segue destinationViewController];
// Do any table setup here, such as injecting the data array into a property on the tableView.
}
}
If instead you have been creating a different UITableView in code, what you will see is an unpopulated UITableView that follows the specifications set up in the storyboard (e.g., row height spacing will be correct) and which is responding to user interaction, but is empty. The empty one is the one being initialised automatically for you by the storyboard, and meanwhile you've been creating another UITableView somewhere else:
// DON'T DO IT THIS WAY IF YOU'RE USING STORYBOARD.
- (void)viewDidLoad {
[super viewDidLoad];
// Incorrectly creating a tableview child table view that won't be the one presented.
self.myTableView = [MYTableViewClass new];
// ...further configuration of the table.
}
If you follow this incorrect path, the other UITableView you are creating is being built in memory, and populated with your data array, so you will see all the NSLog statements from that process and be able to see a UITableView in memory with the correct number of objects and so on as you step through the executing code, but what is hard to pick up is you're not looking at the one being presented to the user. So can be tricky to track down. :)
Just remove the code above, implement prepareForSegue:sender: and the universe will return to being a predictable place.
If you add UITableView inside the UIViewController, you need to set the frame size of the UITableView same as the frame size of the view inside the UIViewController, otherwise the tableview size may be 0, cannot display anything.
You can set the frame size if you create the UITableView by storyboard in your case:
- (void)viewDidLoad {
[super viewDidLoad];
// Set tableview delegate and datasource here
menuTableView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}

How to set up UITableView within a UIViewController created on a .xib file

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.

Resources