I have ViewController and TableViewController. In ViewController i have a 2 buttons and 2 textfields, when button1 is clicked it will navigate to UITableView with static data like (Apple, Samsung, Blackberry, Windows),and button2 is clicked it will navigate to UITableView static data (Doctor, Engineer,Businessman, Employee)when i select any of the row it should be displayed in the textfield1 of button1 clicked and textField2 of button2 clicked ViewController. below is what i have tried as am learning, i don't know wheather it is correct or not.
CustomerVC.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)button1Click:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *txtField1;
- (IBAction)button2Click:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *txtField2;
CustomerTableVC.h
#import <UIKit/UIKit.h>
#interface DetailsViewController : UITableViewController
#end
CustomerTableVC.m
#import "DetailsViewController.h"
#interface DetailsViewController ()
{
NSArray *array1,*array2;
}
#end
#implementation FamilyDetailsViewController
- (void)viewDidLoad {
[super viewDidLoad];
array1=[[NSArray alloc]initWithObjects:#"Apple",#"Samsung",#"Blackberry",#"Windows", nil];
array2=[[NSArray alloc]initWithObjects:#"Doctor",#"Engineer",#"Businessman",#"Employee", nil];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array1 count];
return [array2 count];
}
- (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=[arrqy1 objectAtIndex:indexPath.row];
cell.textLabel.text=[arrqy2 objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.navigationController popViewControllerAnimated:YES];
}
You should use Unwind segue to pass data back from your tableview controller..
Steps to follow:
Suppose A & B are two controllers and you first navigated from A to B with some data. And now you want to POP from B to A with some data.
Unwind Segues is the best and recommended way to do this.
Here are the steps.
Open A.m
define following method
#IBAction func unwindSegueFromBtoA(segue: UIStoryNoardSegue) {
}
open storyboard
Select B ViewController and click on ViewController outlet. press control key and drag to 'Exit' outlet and leave mouse here. In below image, selected icon is ViewController outlet and the last one with Exit sign is Exit Outlet.
You will see 'unwindSegueFromBtoA' method in a popup . Select this method .
Now you will see a segue in your view controler hierarchy in left side. You will see your created segue near StoryBoard Entry Piont in following Image.
Select this and set an identifier to it. (suggest to set the same name as method - unwindSegueFromBtoA)
Open B.m . Now, wherever you want to pop to A. use
self.performSegueWithIdentifier("unwindSegueFromBtoA", sender: dataToSend)
Now when you will pop to 'A', 'unwindSegueFromBtoA' method will be called. In unwindSegueFromBtoA of 'A' you can access any object of 'B'.
That's it..!
Try using delegate.
1. Declare delegate on Tableview controller's.
In Custom Vc
Declare FamilyViewController.delegate = self;
self.view presentviewcontroller = familyviewController;
Define the delegate function (eg. detailsselected())
Inside the detailsSelected dismissViewController.
In FailyDetailsViewController:
Inside the didselectRowAtIndexPath : call the "detailsSelected" function and pass the selected values.
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 have a custom uitableviewcell and subclassed, and it is containing a uitextfield and delegate is also set, now when return key on keyboard is pressed I want to try few things
perform a segue(but issue is I am in uitableviewcell subclass).
modally present another view controller(but issue is uitableviewcell
do not allow this).
I want to display uiactionsheet(but again limitation is
uitableviewcell).
If i get rootviewcontroller reference then rootviewcontroller's view itself not displayed or not the active view so any thing you do will not present on screen, active view is required.
You could use a block property on your cell that is fired whenever your custom button action occurs. Your cell's block property might look something like this:
#interface CustomTableViewCell : UITableViewCell
#property (nonatomic, copy) void (^customActionBlock)();
#end
Your cell would then invoke this block from the custom button action like this:
#implementation CustomTableViewCell
- (IBAction)buttonTapped:(id)sender {
if ( self.customActionBlock ) {
self.customActionBlock();
}
}
#end
Then finally, you set the block in -cellForRowAtIndexPath: back in your view controller (or wherever) like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"customCell" forIndexPath:indexPath];
cell.textLabel.text = [self.colors objectAtIndex:indexPath.row];
cell.customActionBlock = ^{
NSLog(#"Do the stuff!");
// present view controller modally
// present an action sheet
// etc....
};
return cell;
}
One word of caution, though. If you use blocks you run the risk of strongly referencing self and creating a memory leak. Blocks are fun and easy to use but you have to play by their rules. Here are some resources to help you get familiar with them:
Retain cycle on `self` with blocks
Reference to self inside block
http://aceontech.com/objc/ios/2014/01/10/weakify-a-more-elegant-solution-to-weakself.html
http://fuckingblocksyntax.com
You can attach action to your buttons even if they are in a tableView
[cell.button addTarget:self action:#selector(presentController:) forControlEvents:UIControlEventTouchUpInside];
presentController is referring to an IBAction
- (IBAction)presentController:(id)sender
{
//present
}
Implement button action in Tableview SuperClass.
Or You can use Custom delegate in UITableViewCell subclass. In UITableView Subclass declare a protocol.
#protocol customCellDelegate <NSObject>
#required
-(void)selectedButtonInIndexPath : (NSIndexPath *)indexpath;
#end
Set this property in UITableView Subclass
#property (nonatomic, strong)NSIndexPath *indexpath;
#property (nonatomic, strong) id <customCellDelegate> delegate;
And then in Your UITableView Subclass Button action add This lines
if(self.delegate){
[self.delegate selectedButtonInIndexPath: self.indexpath];
}
And in your tableview datasource method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Implement this code
cell.delegate = (id)self;
cell.indexpath = indexPath;
And in Uitableview super class just implement this method
-(void)selectedButtonInIndexPath : (NSIndexPath *)indexpath{
//display uiimagepickercontroller modally or anything else here
}
Already manage to pass input text from first VC to second VC with tableview.
First VC do not have tableview.
First VC:
UItextField - user type some name.
UIButton *add - button with segue (prepareForSegue)
Second VC:
TableView displaying input text from first VC with prepareForSegue
Question:
Tableview displays only one row at the time, so when i click back to input another name, and click add buton, tableview obviously gets reset and does not remember first input text. So how get tableview to remember names and put it in other rows. I don't know should i type code in prepareForSegue, or make delegate in first VC. Please explain in detail. Thank you alot.
I believe there are many ways to achieve this, if you want to persist data maybe core Data is your best bet, however if its just a simple logic then I suggest you using delegates.
ViewController
Interface
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *dataTextField;
#property (nonatomic) NSMutableArray *items;
- (IBAction)AddData:(id)sender;
#end
Implementation
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_items = [[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)AddData:(id)sender {
if ([self.dataTextField.text length]> 0) {
[_items addObject:self.dataTextField.text];
[self performSegueWithIdentifier:#"tableSegue" sender:self];
}else{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Error"
message:#"You must enter some data"
delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertView show];
}
}
- (void)addItemViewController:(TableViewController *)controller didFinishSelectingItem:(NSMutableArray *)item selectedTag:(int)tag{
NSLog(#"DATA=%#", item);
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"tableSegue"]){
TableViewController *controller = (TableViewController *)segue.destinationViewController;
controller.items = _items;
}
}
#end
TableViewController
Interface:
#protocol TableViewControllerDelegate <NSObject>
- (void)addItemViewController:(id)controller didFinishSelectingItem:(NSMutableArray *)item selectedTag:(int)tag;
#end
#interface TableViewController : UITableViewController
#property (nonatomic, weak) id <TableViewControllerDelegate> delegate;
#property (nonatomic) NSMutableArray *items;
#end
Implementation
#implementation TableViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.items count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController popViewControllerAnimated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
[[cell textLabel] setText:_items[indexPath.row]];
return cell;
}
#end
View controllers are part of the controller layer of your application. They do not do "business logic" — heavy processing or more-persistent storage of data, whether to disk or just for that session.
The model section of your application handles that. Each view controller gets and sets data via the model. There should be no ongoing conversations between view controllers*; anything beyond things you would specify to an init is indicative of a broken design.
So you're asking the wrong question.
You would have a model that somehow vends the items that should go into the first view controller. You will have a second view controller that knows how to edit one item. The level of communication from first to second will be "this is the item you should be editing".
It is the responsibility of the first view controller and the model to ensure that it can keep its display up to date. The second view controller is responsible only for modifying its record. It shouldn't need to communicate anything whatsoever to the first view controller.
Whether you do that by pulling results from the model on every viewWillAppear, by some sort of live observation, by notifications emanating outward from the model or by some other means entirely doesn't matter.
(* subject to caveats where you've used containment, e.g. changes to the title that a view controller has but which is shown by a navigation controller are technically an ongoing conversation)
i have this simple code in the didSelectRowAtIndexPath method:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
NSString *selected = #"test";
NSLog(#"You choose: %#", selected);
}
This is my ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
IBOutlet UITableView *tableData;
}
#end
When i run the App, the TableView display all data, but then i cliked in a cell the method above doesn't run (?)
Have you set the delegate for the tableview in your storyboard, select your table view right click and drag to the view controller and you should see the option to set dataSource delegate and tableviewdelegate - I forget the exact names.
e.g.: thats part of my code, but should show you what you need to do. You need to hand over the data somewhere.
NSDictionary *oneDict = [_noteBookArray objectAtIndex:indexPath.row];
NSString *touchString = [oneDict objectForKey:#"value"];
NSString *dateString = [oneDict objectForKey:#"timestamp"];
//call the method who does it
[_noteBookViewController setContentAndTimeStampWith:touchString and:dateString];
//set the present View Controller active (the controller who contains the values)
[self presentViewController:_noteBookViewController animated:YES completion:nil];
method from the notebookviewcontroller
- (void)setContentAndTimeStampWith:(NSString *)contentString and:(NSString *)timeStampString
{_textInputView.text = contentString;
_timeStampString = timeStampString;}
got it?
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.