How to pass data between modal view controller - objective-c

This is a noob question.what i want is to pass data from my QuizViewcontroller to QuizModalViewController.i was successful in creating a normal modal view controller but having problem when passing data between the two..below is my code.
QuizViewController
-(IBAction)button3Clicked:(id)sender
{
QuizModalViewController *mvid=[[QuizModalViewController alloc]initWithNibName:#"QuizModalViewController" bundle:nil];
mvid.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:mvid animated:YES];
}
QuizModalViewController
- (IBAction)goBackToView
{
[self dismissModalViewControllerAnimated:YES];
//[controller loadQuestion:currentQuestionIndex+1];
}

-(IBAction)button3Clicked:(id)sender
{
QuizModalViewController *mvid=[[QuizModalViewController alloc]initWithNibName:#"QuizModalViewController" bundle:nil];
mvid.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
mvid.theDataYouWantToPass = theData; // this is how you do it
[self presentModalViewController:mvid animated:YES];
}
Note that theDataYouWantToPass must be a property declared in the QuizModalViewController.h file.

You can also use the -(void)prepareForSegue:... - Method to share data between controllers.
For Example:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"Your_Identifier"]) {
TestViewController *controller = [segue destinationViewController];
NSArray *array = [[NSArray alloc] initWithObjects:#"",nil];
controller.objectInTestViewController = array;
}
}
Hope this helps someone....

Make your QuizModalViewController available at class scope instead of using a local variable.
Then in the goBackToView: you can access the controller's content prior to dismissing it.
By the way: in your code you're leaking mvid. Release it after presenting it modally.

Related

Trying to pass Data from current VC to the next but first checking if the user inputs the correct info

I am trying to pass data from the current View Controller to the next View Controller using an IBAction because I also need to check if the user is using the correct User Email and ID before going to the second View Controller. I am still new to Objective-C and Xcode. I thought this would work but it doesn't. It will not pass the number 15 to the second VC. I would like to for it to be something like this. Please help me figure out a way to do this. This is actually for my Final Project that is due today. Lol
- (IBAction)signInButtonPressed:(id)sender {
DatabaseManager *data = [DatabaseManager new]; // A DB Using SQLite3
if (![self.studentEmailField.text isEqualToString:#""] && ![self.studentMDCID.text isEqualToString:#""]) {
if ([data checkStudentEmail:self.studentEmailField.text checkStudentID:self.studentMDCID.text]) {
StudentMainPageViewController *secoundVC = [StudentMainPageViewController new];
secoundVC.rowInDB = 15;
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *StudentMainPageVC = [mainStoryboard instantiateViewControllerWithIdentifier:#"StudentMainPageID"];
[self presentViewController:StudentMainPageVC animated:TRUE completion:nil];
}
}
}
Try use following solution:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YourSegueIdentifier"])
{
DestinationViewController *dest = [segue destinationViewController];
dest.myData = self.myData;
}
}

How to show the data of a textfield to the label of a tableview cell?

I am new to iOS developing. I am building a project where I want to show the text of a textfield of a view controller to the label of a table view cell of another viewcontroller. Can anyone tell me just the logic how to do that?
Since you haven't posted any code, I will try to explain it to you.
You will have to create event for button, and there you can do something like [self performSegueWithIdentifier:#"yourSegue" sender:self];
Next thing is to create property in your new ViewController that will accept your value.
After that, in your prepareForSegue you can do NSString *text = [self.textField text];, get your new VC from segue.destinationViewController; and assign your value there.
So, in the end you will have :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if(segue.identifier isEqualToString:#"yourSegue"])
{
YourViewController *vc = segue.destinationViewController;
vc.accpetValue = [self.yourTextField text];
}
}
and in your action for button:
- (IBAction)yourButton_pressed:(id)sender
{
[self performSegueWithIdentifier:#"yourSegue" sender:self];
}
If you have tableViewController there, and you want to assign this value to the cell on the same screen, on button you can obtain the value with same way as above, and in you cellAtIndexPath you can do the following:
if(self.yourTextBox && [self.yourTextBox text] && ![[self.yourTextBox text] isEqualToString:#""])
{
cell.textLabel.text = [self.yourTextBox text];
}
else
{
//something else
}
And on your button event you can do
[self.tableView reloadData];
Hope it helps.
If the view controller with the cell is open from the view controller with the textfield, is quite easy.
You can create a property NSString in the second view controller .h and then you can call it when you open this from the first.
SecondViewController * cotroller = [[SecondViewController alloc]init];
controller.string = [textField text];
[self presentViewController:controller animated:YES completion:^{
}]

What's the difference between the back button on UINavigationController and PopTopViewController?

I have a UINavigationController hierarchy, VC1 --> VC2.
VC1 has a table view that I need to reload when VC2 is done with its work, so VC1 has this code:
-(void)viewWillAppear:(BOOL)animated
{
[[self tableView] reloadData];
}
VC2 is essentially working with the server to create a new table row in VC1. When the done button in VC2 is pressed, I call [navController popViewControllerAnimated:YES]. So here's what happens from the user's perspective:
Visit VC2, use it to create a new row for the table in VC1. Press done.
The hierarchy successfully navigates back to VC1, but the tableview does not reload and display the new row.
However, if I then nav forward to VC2, and immediately hit the navController back button, the table does reload and show the new row.
So why does [tableview reload] work on 3 but not 2? Thanks so much.
==
More code in response to answer mentioned below:
In App delegate:
CWLandingVC *lvc = [[CWLandingVC alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:lvc];
[[self window] setRootViewController:navController];
In VC0:
-(void)toSessionMgmtViewController
{
TSessionMgmtViewController *tsmvc = [[TSessionMgmtViewController alloc] init];
[[self navigationController] pushViewController:tsmvc animated:YES];
}
In VC1:
- (IBAction)toCreateSessionView:(id)sender
{
TCreateSession *cs = [[TCreateSession alloc] init];
[[self navigationController] pushViewController:cs animated:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self tableView] reloadData];
}
In VC2:
Finishes working with server...
UINavigationController *navControler = [self navigationController];
[navControler popViewControllerAnimated:YES];
Also, when VC2 is done working with the server, it updates a data store of TSessions called SessionListStore:
- (TSession *)addSession:(NSString *)code withName:(NSString *) name qs:(int)qs
{
TSession *s = [[TSession alloc] initWithName:name code:code numberQuestions:qs];
[_sessions setObject:s forKey:code];
return s;
}
where sessions is a NSNutatbleDictionary in SessionListStore.
Thanks so much in advance.
EDIT: The solution was to trigger the reloadData call from the completion block of Server call.
Please check this answer,
Popping ViewController doesn't call viewWillAppear when going back
Have you added navigation controller to your view controller or view controllers to your navigation controller?
Also, you can set the desired view controller as the delegate of your navigation controller and implement this method.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated

Unable to switch views programmatically using a storyboard?

I am developing a storyboard-based application, using XCode 4.2. I'm new to storyboards, before that I used to switch views by creating a new instance of a class like this:
if (x==1)
{
theClass *theView ;
theView= [[theClass alloc] initWithNibName:nil bundle:nil];
[theView setText:theText];
[reader presentModalViewController:theClass animated:YES]; //where reader is an instance of the ZBar library
}
With storyboards, here is the code I am trying:
if (x==1)
{
[self performSegueWithIdentifier: #"theNewView" sender: self];
}
then:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"theNewView"])
{
[[segue destinationViewController] setText:theText];
[reader presentModalViewController:[segue destinationViewController] animated:YES];
}
}
I made sure that the links are well made and that the prepareforsegue method is called, but even with this code, the new view is not being loaded?
Don't call presentModalViewController in your prepareForSeque method - this method is for passing information to the new view controller.
See post.
Useful learning weblog post, for getting started with a storyboard.

It is possible to use an existing ViewController with PerformSegueWithIdentifier?

I use the method performSegueWithIdentifier:sender: to open a new ViewController from a storyboard-file programmatically. This works like a charm.
But on every time when this method is being called, a new ViewController would be created. Is it possible to use the existing ViewController, if it exista? I don't find anything about this issue (apple-doc, Stack Overflow, ...).
The Problem is:
On the created ViewController the user set some form-Elements and if the ViewController would be called again, the form-elements has the initial settings :(
Any help would be appreciated.
Edit:
I appreciate the many responses. Meanwhile, I'm not familiar with the project and can not check your answers.
Use shouldPerforSegueWithIdentifier to either allow the segue to perform or to cancel the segue and manually add your ViewController. Retain a pointer in the prepareForSegue.
... header
#property (strong, nonatomic) MyViewController *myVC;
... implementation
-(BOOL) shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if([identifier isEqualToString:#"MySegueIdentifier"]){
if(self.myVC){
// push on the viewController
[self.navigationController pushViewController:self.myVC animated:YES];
// cancel segue
return NO;
}
}
// allow the segue to perform
return YES;
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"MySegueIdentifier"]){
// this will only be called the first time the segue fires for this identifier
// retian a pointer to the view controller
self.myVC = segue.destinationViewController;
}
}
To reuse an existing UIViewController instance with a segue create the segue from scratch and provide your own (existing) destination (UIViewController). Do not forget to call prepareForSegue: if needed.
For example:
UIStoryboardSegue* aSegue = [[UIStoryboardSegue alloc] initWithIdentifier:#"yourSegueIdentifier" source:self destination:self.existingViewController]
[self prepareForSegue:aSegue sender:self];
[aSegue perform];
Following code makes singleton view controller.
Add them to your destination view controller implementation, then segue will reuse the same vc.
static id s_singleton = nil;
+ (id) alloc {
if(s_singleton != nil)
return s_singleton;
return [super alloc];
}
- (id) initWithCoder:(NSCoder *)aDecoder {
if(s_singleton != nil)
return s_singleton;
self = [super initWithCoder:aDecoder];
if(self) {
s_singleton = self;
}
return self;
}
I faced this problem today and what I have done is to create the view controller manually and store it's reference.
Then every time I need the controller, check first if exists.
Something like this:
MyController *controller = [storedControllers valueForKey:#"controllerName"];
if (!controller)
{
controller = [[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:NULL] instantiateViewControllerWithIdentifier:#"MyControllerIdentifierOnTheStoryboard"];
[storedControllers setValue:controller forKey:#"controllerName"];
}
[self.navigationController pushViewController:controller animated:YES];
Hope it helps.
Create a property for the controller.
#property (nonatomic, weak) MyController controller;
And use some kind of lazy initialization in performSegueWithIdentifier:sender
if (self.controller == nil)
{
self.controller = [MyController alloc] init]
...
}
In this case, if controller was already created, it will be reused.
Firstly you would be going against Apple's design in Using Segues: "A segue always presents a new view controller".
To understand why it might help to know that what a segue does is create a new view controller and then the perform calls either showViewController or showDetailViewController depending on what kind of segue it is. So if you have an existing view controller just call those methods! e.g.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Event *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
self.detailViewController.detailItem = object;
[self showDetailViewController:self.detailViewController.navigationController sender:self];
}
You would need to make the Viewcontroller into a singleton class.