Transferring Data Back to Original View - objective-c

So I am able to transfer the data from the first view to the second view like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Check Mark Segue"])
{
NSLog(#"Transfering Data");
AutoRenewDrop *controller = segue.destinationViewController;
controller.transferData = self.renewDate.text;
}
}
However, I try to transfer a new value back to renewDate.text when the user hits done and the transferData is working correctly but the renewDate.text does not change. Here is the code that I am using to transfer the data back:
-(IBAction)done:(UIStoryboardSegue *)segue {
[self.navigationController popViewControllerAnimated:YES];
AddR *add = [[AddR alloc] init];
add.renewDate.text = transferData;
}
Can someone tell me how to fix this?

You need to add a property that contain a reference of the first view into the second view :
#interface AutoRenewDrop
#property(weak, nonatomic) AddR *callerView;
#end
And then in the done method of the second view you can just update the variale in the caller view :
-(IBAction)done:(UIStoryboardSegue *)segue {
[self.navigationController popViewControllerAnimated:YES];
callerView.renewDate.text = transferData;
}
Of course when you instantiate the second view you will have to set the reference, in this way :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Check Mark Segue"])
{
NSLog(#"Transfering Data");
AutoRenewDrop *controller = segue.destinationViewController;
controller.transferData = self.renewDate.text;
controller.callerView = self; //Here, you are passing the reference to this View
}
}

You should use a delegate.
You can read a pretty good tutorial about protocols and delegates here.
Lets say you have 2 ViewControllers - VC1 and VC2, and lets say that VC1 displays VC2.
In VC2.h
#protocol VC2Delegate <NSObject>
- (void)updateData:(id)theData;
#end
#interface
#property (nonatomic, weak) id<VC2Delegate> delegate;
#end
In VC2.m
#syntesize delegate;
- (void)done
{
[delegate updateData:myData];
}
In VC1.h
#interface VC1 : UIViewController<VC2Delegate>
In VC1.m
- (void)goToVC2
{
VC2 *vc2 = [[VC2 alloc] init];
vc2.delegate = self;
// present vc2
}
- (void)updateData:(id)data
{
// update what you need
}

Related

How to continouse pass value from one ViewController to second Viewcontroller and automatic close, dismiss 2nd ViewController

I try to pass data from one ViewController to secondControler however seem it not work. I use NSNotification.
- 2 Controller have same class "ViewController"
In viewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ProcessBarLoading) name:#"buttonPressed" object:nil];
}
-(void)ProcessBarLoading{
_labelTest.stringValue = #"TESTING";
}
- (IBAction)test:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"buttonPressed" object:self];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
}
When run program and press button, there're no update Label Text at all. Do you know why and how I can fix.
New Code:
In SecondViewController.m
#interface SencondViewController ()
#end
#implementation SencondViewController
#synthesize progressValue;
#synthesize labelView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
labelView.stringValue =progressValue;
}
In FirstViewCOntroller:
- (IBAction)test:(id)sender {
self->uide = #"0";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:self->uide];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
SencondViewController * secondVC = segue.destinationController;
secondVC.progressValue = uide;
}
}
- (IBAction)test2:(id)sender {
uide = #"80";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:uide];
[self.view displayIfNeeded];
}
So whether I press Button 1(test) other Button2 (test2) alway show new view with update value. What I need is only show 1 view.
Why do you need use a nsnotification the easy way is use a prepareForSegue or Delegation
This is an examample
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"myId"]) {
SecondViewController *vc = segue.destinationViewController;
vc.myDataToPass = self.myValueInMyFirstViewController;
}
}
Notification pattern is not recommended for doing this. Use notification
when you want to pass some data to multiple objects on some event.
To solve this problem:
Step 1:
You should change your View Controller names to FirstViewController and SecondViewController, and have a property declared in your SecondViewController whose value you want to set from the FirstViewController.
Step 2:
Finally, in the prepare for Segue method of the FirstViewController, set the data.
In Objective-C, you can try this code:
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//This will trigger the prepareForSegue method
-(IBAction) someButtonClick {
[self performSegueWithIdentifier:#"YourSequeId" sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController * secondVC = segue.destinationViewController;
secondVC.someValue = #"PassYourValueHere";
}
#end
and in the header file of the SecondViewController, declare the property:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (nonatomic,strong) NSString *someValue;
#end
In the implementation file of the SecondViewController, write:
#import "SecondViewController.h"
#interface SecondViewController ()
#property (nonatomic,weak) IBOutlet UITextField *yourTextField;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.yourTextField.text = self.someValue
// Do any additional setup after loading the view.
}
#end

call popover and send back variable to previous uiview

I have an UITableViewController created with storyboard.
Than I have an anchor that call a popOver created with storyboard as well. The popover is another UItableViewController, when I click on a row I should call back the first controller and pass an object.
I have tried this in the popover object:
(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"Fortune"]){
NSIndexPath *indexPath = (NSIndexPath *)sender;
ASFortuneTeller * aController = [segue destinationViewController];
[aController setWYPT:[allWYPTs objectAtIndex:indexPath.row]];
}
}
Basically I need to pass a NSMutableDictionary bag to the first UITableViewController.
But I have noticed that in this way I create a new ASFortuneTeller object , that is not what I want... I want just to call back the first controller and pass an object.
How can I do it?
A quick solution (when it involves always the same two classes) could be:
In the .h file of the first view controller, define a method (or just a property):
-(void)selectedWYPT:(NSMutableDictionary*)wypt;
Within the .h file of your second view controller make a property
#property FirstUIViewController *firstView;
In the first view controller, you will open the second view controller via a segue, so there you can use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segueIdentifier"]) {
SecondUIViewController *destination = segue.destinationViewController;
destination.firstView = self;
}
}
When the row is selected in the second view you can use
if (self.firstView)
[self.firstView setWYPT:[allWYPTs objectAtIndex:indexPath.row]];
to pass the data back to the first view.
As said, this would be a quick solution when always the same two classes are involved.
An other way would be to use protocols. When the first view controller won't always be FirstUIVierController, you may use something like this:
SecondUIViewController.h
#class SecondUIViewController;
#protocol SecondUIViewControllerDelegate <NSObject>
-(void)secondUIViewController:(SecondUIViewController*)controller didSelectWYPT:(NSMutableDictionary*)wypt;
#end
#interface SecondUIViewController : UIViewController
#property id<SecondUIViewControllerDelegate> delegate;
#end
SecondUIViewController.m
where the row is selected:
if (self.delegate && [self.delegate respondsToSelector:#selector(secondUIViewController:didSelectWYPT:)])
[self.delegate secondUIViewController:self didSelectWYPT:[allWYPTs objectAtIndex:indexPath.row]];
AnyOtherUIViewController.h
#import "SecondUIViewController.h"
#interface AnyOtherUIViewController : UIViewController <SecondUIViewControllerDelegate>
...
...
AnyOtherViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segueIdentifier"]) {
SecondUIViewController *destination = segue.destinationViewController;
destination.delegate = self;
}
}
-(void)secondUIViewController:(SecondUIViewController*)controller didSelectWYPT:(NSMutableDictionary*)wypt {
//do something with the data
}

How can I send selectedSegmentIndex to containerView in Objective-c?

I have a containerView into my viewController. My viewController has a UISegmentedControl.
How can I send this selectedSegmentIndex selected at this moment and everytime when I change this?
I', trying with a property in the next class with prepareForSegue but this only send on first load..
Thanks!
Then Edit I'm getting: -[ViewController containerViewDidChangeSegmentIndex:]: unrecognized selector sent to instance 0x7f8db16286d0
FirstViewController (This contains A select and a containerView)
ViewController.h
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UISegmentedControl *select;
#property (weak, nonatomic) IBOutlet UIView *container;
#property(nonatomic, assign) ContainerViewController * classLevelReference;
#end
ViewController.m
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[_select addTarget:self action:#selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
}
- (void)segmentChanged:(UISegmentedControl *)segment{
//since you've reference to your container view here, you can directly call its method here:
[self.classLevelReference containerViewDidChangeSegmentIndex:segment.selectedSegmentIndex];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//don't forget to check the segue id, if you've multiple segues
ContainerViewController *containerView = [segue destinationViewController];
self.classLevelReference = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
ContainerViewController.h
#interface ContainerViewController : UIViewController
- (void)containerViewDidChangeSegmentIndex:(NSInteger)updatedIndex;
#end
ContainerView.m
#implementation ContainerViewController
- (void)containerViewDidChangeSegmentIndex:(NSInteger)updatedIndex{
//Do whatever you want with your updated index
NSLog(#"changing");
}
#end
You might want to make a method in your ContainerViewController.h like this:
#interface ContainerViewController:UIViewController
//.....other implementation here.
- (void)containerViewDidChangeSegmentIndex:(NSInteger)updatedIndex;
#end
Now implement this method in your ContainerViewController.m like this:
- (void)containerViewDidChangeSegmentIndex:(NSInteger)updatedIndex{
//Do whatever you want with your updated index
}
Now in your prepare for segue, save the reference to your ContainerViewController in a class-level variable :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//don't forget to check the segue id, if you've multiple segues
ContainerViewController *containerView = [segue destinationViewController];
self.classLevelReference = containerView;
}
Lastly in the FirstViewController.m, tell the container view when segment index changes.
- (void)viewDidLoad{
//.....your other implementation here.....
//add a listener to your segment's value changed action
[youregements addTarget:self action:#selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
}
- (void)segmentChanged:(UISegmentedControl *)segment{
//since you've reference to your container view here, you can directly call its method here:
[self.classLevelReference containerViewDidChangeSegmentIndex:segment.selectedSegmentIndex];
}
Important: you might've different names for the ContainerViewController and FirstViewController in your case, just apply the changes carefully.
Happy coding!

addObject to NSMutableArray doesn't work with storyboards

I have a table in my root view controller which has the "add" button mapped to another view controller which has text field to input the name of the list and a save button. That save button is mapped back to the main controller. When the data is passed back to the main controller, it doesn't add the item to the table.
This is what my table view controller's viewDidLoad look like:
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.allowsMultipleSelectionDuringEditing = YES;
if (!self.listArray) self.listArray = [[NSMutableArray alloc] init];
[self.listArray addObject:#"New Item"];
[self.tableView reloadData];
[self updateButtonState];
}
This adds the "New Item" to the list and shows up in the table. But when I pass the listname from the segue, I can see the log entry "Adding..." but doesn't add the item to the table. Here's the method for add a new item from a segue.
-(void) addList:(NSString *)listName
{
NSLog(#"Adding %#", listName);
[self.listArray addObject:listName];
[self.tableView reloadData];
}
Prepare for segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
LSNewListViewController *sourceView = [segue sourceViewController];
LSMainViewController *destView = [segue destinationViewController];
[destView addList:[[sourceView listName] text]];
}
Rather than using a storyboard segue to push another view controller, try setting a protocol in your "add" view controller. Then set your "main" view controller as the delegate and handle the adding there. From there you can connect the "add" button to call the delegate method and pop the view controller.
LSNewListViewController.h
#protocol LSNewListViewControllerDelegate;
#interface LSNewListViewController : UIViewController
#property (nonatomic, weak) id <LSNewListViewControllerDelegate> delegate;
#end
#protocol LSNewListViewControllerDelegate <NSObject>
#optional
- (void)didAddToList:(NSString*)item;
#end
LSNewListViewController.m
#implementation LSNewListViewController
// Hooked up to the Add button in the storyboard (touchUpInside)
- (IBAction)addToListAction:(id)sender {
if ([self.delegate respondsToSelector:#selector(didAddToList:)]) {
[self.delegate didAddToList:[sourceView listName] text]];
}
}
#end
LSMainViewController.h
#import "LSNewListViewController.h"
#interface LSMainViewController : UIViewController <LSNewListViewControllerDelegate>
#end
LSMainViewController.m
#implementation LSMainViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
LSNewListViewController *destView = [segue destinationViewController];
destView.delegate = self;
}
// Delegate method
- (void)didAddToList:(NSString*)item {
NSLog(#"Adding %#", listName);
[self.listArray addObject:listName];
[self.tableView reloadData];
[self.navigationController popViewControllerAnimated:YES];
}
#end

How to set a UIStepper value in destination view using prepareForSegue method?

In my presenting view controller, I have the following prepareForSegue function
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"goToView2"]){
ViewController2 *controller2 = [segue destinationViewController];
controller2.multiplierStepper.value = 7.0;
controller2.randomString = #"string set from Scene 1";
}
}
In ViewController2 there is an outlet for my UIStepper's value and an NSString
#property (strong, nonatomic) IBOutlet UIStepper *multiplierStepper;
#property (strong, nonatomic) NSString *randomString;
In ViewController2.m viewDidLoad, I am testing the values set above by the presenting view controller
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"in viewDidLoad: self.multiplierStepper.value: %f", self.multiplierStepper.value);
NSLog(#"in viewDidLoad: randomstring: %#", self.randomString);
}
The console output works nicely for the NSString, but the UIStepper value always shows the initial value defined in the Interface Builder (1).
[10682:f803] in viewDidLoad: self.multiplierStepper.value: 1.000000
[10682:f803] in viewDidLoad: randomstring: string set from Scene 1
The answer is probably glaringly obvious, but I cannot figure out how to set the value of a stepper in my destination view controller from the presenting view controller.
Any ideas what I'm doing wrong?
Do not set directly the value of the UIStepper in the the prepareForSeque method , it will not work !
You have to declare a property that will contains the value and then set the value of the stepper in the viewDidLoad event of the second controller ...
First of all declare an additional property to your second view controller (ViewController2) header file :
#property (nonatomic) double stepperValue;
Then set the property value :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"goToView2"]){
ViewController2 *controller2 = [segue destinationViewController];
controller2.stepperValue = 7.0;
controller2.randomString = #"string set from Scene 1";
}
}
Then in the destination viewController (ViewController2) :
- (void)viewDidLoad
{
multiplierStepper.value = [self stepperValue];
}
Note
Bear in mind that the best thing for encapsulation would be declaring the IBOutlet as private member of the class, to avoid that a client of the class can access directly the IBOutlet; to make an IBOutlet private you have to declare it in a class extension in the .m file ...