iOS passing data between two Views - ios

I'm using two views (view controllers VC1 and VC2) and passing data from VC1 to VC2
I stored the values for two variables in VC2
//VC1 store obj to VC2
self.VC2.twtid=ide;
self.VC2.urlString=[[NSURL alloc] initWithString:vurl];
I received the values after VC2 was shown.
My problem is when I click in any cell in VC1 for the second time.
When I navigate back to VC1(tableview) again and tried to select cell, the values aren't stored again.
//VC.h I declare the two var
#property(strong, nonatomic) NSNumber *twtid;
#property(strong, nonatomic) NSURL *urlString;
note: I didn't use prepareForSegue.without Segue!!

Use global variables othereise use Segue methods.

ViewController2 *VC2 = (ViewController2 *)[self.storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
VC2.url = urlString; // use your variable over here, this is just and example
[self presentViewController:VC2 animated:YES completion:^{ }];
[self.navigationController pushViewController:VC2 animated:YES];
user presentViewController or pushViewController as per your requirement

You don't need to store the VC2 as VC1's property, just init it every time.

Related

iOS: how to detect if viewcontroller appears after pop or dismiss

I have a view controller VC1 and I am doing following two operations on it:
Push another view controller VC2 from VC1's navigation controller by calling
[VC1.navigationController pushViewController: animated:YES];
Present another view controller VC3 from VC1 by calling.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:VC3];
[VC1 presentViewController:navController animated:YES completion:nil];
Now when I am coming from VC2 to VC1 I am calling
[VC2.navigationController popViewControllerAnimated:YES];
and from VC3 to VC1 I am calling
[VC3.navigationController dismissViewControllerAnimated:YES completion:nil];
My question is when I am coming back to VC1 how do I know that whether I am coming from VC2(by dismissing) or VC3(by popping)?
Note: VC1 is loaded as child view controller inside a parent view controller VC4.
The best way would be to have the childViewController call back to the presenting view controller. By doing this the childViewController will not need to know the implementation details of whether it was presented modally or in a navigation stack etc.
With blocks it would look something like
#interface VC2 : UIViewController
#property (nonatomic, copy) void (^completion)(VC2 *viewController);
#end
You would set this block up something like this
VC2 *viewController = VC2.new;
viewController.completion = ^(VC2 *viewController) {
[viewController.navigationController popViewControllerAnimated:YES];
};
[VC1.navigationController pushViewController:viewController animated:YES];
Now where you was previously calling
[VC2.navigationController popViewControllerAnimated:YES];
You instead call
self.completion(self);
You put any logic you want to be associated with coming back from a specific viewController inside the completion handler

Get ViewController from Storyboard

I have two ViewControllers, which aren`t (directly) connected with a Segue. But I want to change a String in the second VC, which i get in the first one. My try was:
#import "secondViewController.h"
#interface firstViewController ()
#property NSString* originalString;
#end
#implementation firstViewController
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc = [secondViewController new];
svc.anotherString = self.originalString;
}
But it dosent work, because I've only created a instance of the second VC, so the value was not saved. Also I can`t use the Storyboard ID, because I use Xcode 5.
I have a menuVC from which you can get to the firstVC and the secondVC. And from the firstVC I can go back (with the navigationbackbarbutton) to the menu. so: menu->firstVC->menu. menu->secondVC->...->menu
My try with StoryboardID:
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
secondViewController* svc =[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"secondVCSrorybradID"];
svc.anotherString = self.originalString;
}
you can pass the string to second view controller with this code.
secondViewController* svc =[self.storyboard instantiateViewControllerWithIdentifier:#"Your Second VC's Storyboad ID"];
svc.anotherString = self.originalString;
[self presentViewController:svc animated:YES completion:nil];
//you have to create anotherString property in second View Controller's .h File.
now you can get the string of originalString to second VC. Now you can get this value back second VC to first VC.
hope this helps you.
You should pass your data successively through your UIViewControllers navigation. If, for example, you have a navigation like FirstVC > SecondVC > ThirdVC :
In your FirstVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((SecondVCClass*) segue.destinationViewController).secondVCString = _firstVCString;
}
With secondVCString being a #property in your second ViewController.
In your SecondVC.m, use :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
((ThirdVCClass*) segue.destinationViewController).thirdVCString = _secondVCString;
}
With of course thirdVCString being a #property in your third ViewController.
Edit:
As you updated your question, here is what I suggest :
In your MenuVC, add this :
#property (nonatomic, weak) NSString *importantString;
In your FirstVC and SecondVC, add this :
#property (nonatomic, weak) MenuVCClass *menu;
When you push to FirstVC or SecondVC, use prepareForSegue to set the destination's view controller menu property to your menu :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"FirstSegue"])
((FirstVC*) segue.destinationViewController).menu = self;
else if ([segue.identifier isEqualToString:#"SecondSegue"])
((SecondVC*) segue.destinationViewController).menu = self;
}
In FirstVC or SecondVC, you can change the NSString value from your menu using _menu.importantString = #"";
You should never use new to create a view controller.
If you're using storyboards but not using segues, you can still create a view controller from the storyboard and invoke it.
Use the method instantiateViewControllerWithIdentifier: to create an instance of the target view controller. The set the properties you want to set, and finally make a call to display it (present it modally, push it onto the navigation stack, or whatever is appropriate for your program.)

Failure to pass variables/values to another view controller (not working)

Object: change the label's text in ViewControllerB
(In the ViewControllerA.m)
- (IBAction)ReturnToMenu
{
ViewControllerB *ViewControllerB =
[self.storyboard instantiateViewControllerWithIdentifier:#"ViewControllerB"];
ViewControllerB.scorelabel.text=#"WHY IS IT NOT WORKING";
[self presentViewController:GameOverViewController animated:YES completion:nil];
}
Well, this isn't working. I've exhausted all my options. This is such an elementary question, but please help me out.
P.S. #"Why is it not working" is just a temporary thing, a variable from ViewControllerA is supposed to take its place.
P.P.S. I tried out Passing Data between View Controllers, but it didn't work. I'm not sure what I'm doing wrong here
You should not try to manipulate another view controller's views directly. It's bad design, and in many cases (like yours) it doesn't work.
Instead of setting a label's text, add a string property "score". Set that after instantiating the VC.
Then, in "ViewController8"s viewWillAppear method, install the score property into the label.
Problem solved.
Here I present a modal view controller from my main view controller to show locations which I previously got from foursquare api.
LocationPickerVC *vc = (LocationPickerVC*)[self.storyboard instantiateViewControllerWithIdentifier:#"modal"];
if([vc respondsToSelector:#selector(setLocations:) ])
vc.locations = items;
[self.formSheetController presentViewController:vc animated:YES completion:nil];
[EDIT]
Make sure you set storyboard id in your storyboard (for the code below it is "modal"). Also my LocationPickerVC has this interface.
#interface LocationPickerVC : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property(strong, nonatomic) NSMutableArray *locations;
#end
OK, try this:
In your ViewController1.h that the property score is declared, add this:
+ (ViewController1 *) sharedController;
In your ViewController1.m add this method:
+ (ViewController1 *)sharedController
{
static ViewController1* staticVar = nil;
if (staticVar == nil)
staticVar = [[ViewController1 alloc] init];
return staticVar;
}
Now, where ever in other ViewControllers you need something from ViewController1, import the header, and then get the property like this:
[[ViewController1 sharedController] score]

Delegation between ViewControllers

i know how to set up a "normal" delegation between to ViewController, which are directly dependent. So if i say, i have to send a message from one view to its upper one, i know how to do this.
But how do i set up a delegate, if there are more ViewControllers between the two?
So m let's say i have this setup according to the scheme:
ViewController1 -> ViewController2 -> ViewController3
(via ButtonPressed) (via ButtonPressed)
If i want to set a (for example) NSString in VC1 from VC2, i just write into the prepareForSegue, where i call the VC2:
VC2.delegate = self;
But what do i do when i want to transfer Data between VC3 and VC1 without having to change VC2?
What do i set the delegate for, if it isn't "self"?
I know my description is very bad, but i cannot describe it better.
I just want this: VC1 has one button and a label; the button opens VC2, which has one button too, but no label; this VC2Button shows VC3; And with a touch to the button in the VC3 i want to change the label in VC1. But without having to set a delegte to VC2 and then another to VC1, i know how this works.
Hope you get what i want.
Thanks in advance!
NSNotificationCenter may help if you don't want to maintain too many pointers just to link two unrelated views together.
You can either pass on the delegate from VC2 to VC3 like this:
Inside VC1:
VC2 *vc2 = [VC2 alloc] init];
vc2.delegate = self;
Inside VC2:
VC3 *vc3 = [VC3 alloc] init];
vc3.delegate = self.delegate;
Or you can use target-selector design pattern to achieve this.
Target-Selector way:
Inside VC1:
VC2 *vc2 = [VC2 alloc] initWithTarget:(id)iTarget andSelector:(SEL)iSelector];
Inside VC2: Pass on the target/selector received from VC1
VC3 *vc3 = [VC3 alloc] initWithTarget:(id)iTarget andSelector:(SEL)iSelector];

How do I link an array between two ViewControllers?

I'm a beginner at C# so make sure you explain everything.
Okay, so I have a UIPickerView with its corresponding array of items in my ViewController. When the user clicks "submit", the app is supposed to take them to a SecondViewController, and display the item that they chose in the UIPickerView in a label. The only problem I am having is that I can't seem to link the two ViewControllers together.
I imported my ViewController by using #import into the SecondViewController, but that didn't work. I am getting a "use of undeclared identifer' error. What am I supposed to do to link the two ViewControllers together?
Thanks in advance.
If your first ViewController is the one that's presenting your second ViewController, then you can add a property in the second-view-controller that will be set to the selected value.
In SecondViewController.h
#property (nonatomic) NSString *selectedItemName;
Then, when you're presenting your second-view-controller, also set the value for this property:
SecondViewController *vc2 = [[SecondViewController alloc] init];
vc2.selectedItemName = #"selected item"; //set the actual selected item's value here
[self presentViewController:vc2 animated:YES];
Refer to this answer by Parth Bhatt. I think that should help you:
Passing NSString value between classes
I am re-pasting the answer to make the answer useful in case the link goes off in the future.
Answer from the above link:
Let us use the names of the two viewControllers as FirstViewController and SecondViewController.
Now suppose you push SecondViewController from FirstViewController on a button click then you need to write this code under your button click event:
// In the FirstViewController
- (void)buttonClicked:(id)sender{
SecondViewController *second = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle: nil];
second.secString = firstString;
[self.navigationController pushViewController:second animated:YES];
[second release];
}
Here you need to declare in SecondViewController.h file:
NSString *secString;
and then create a #property
#property (non atomic,strong) NSString *secString;
In SecondViewController.m you need to #synthesize the secString:
#synthesize secString;
Hence this way you also create a getter and setter for secString by creating property and synthesizing it.
Now you can easily access the secString and you can use it anywhere in SecondViewController.
Just to check Try and check if value of firstString is passed to secString, write following code on viewWillAppear: of SecondViewController
NSLog(#"secString: %#",secString);
Let me know if you need more help.
Hope this helps.

Resources