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

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]

Related

pass data between UIViewControllers

Leveraging RESideMenu https://github.com/romaonthego/RESideMenu in my app, now has an issue of passing some urlString related to lists in sideMenuViewControll to show its web page in right UIWebView.
Original codes like below:
case 2: {
navigationController.viewControllers = #[[self.storyboard instantiateViewControllerWithIdentifier:#"second"]];
[self.sideMenuViewController hideMenuViewController];
}
break;
"second" is for secondViewController that has a UIWebView for showing web page at right side. secondViewController has a property: urlString.
My intention is to show its web page when selecting "Profile". Tried several way, however, I can't find one to set urlString after navigationController.viewControllers = #[[self.storyboard instantiateViewControllerWithIdentifier:#"second"]];
How can I set and pass urlString so that it could be used like NSUrl * url = [NSURL URLWithString:urlString]?
First of all import your secondViewController in your first View Controller's .m file
Create in secondViewController's .h file
#property (strong, nonatomic) *NSString passedURL;
Then give the storyboard name in Attribute Inspector.
Now, on button event of profile or whatever
secondViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
svc.passedURL = urlString;
[self presentViewController:svc animated:YES completion:nil];
Thats it. Hope that it works for you.
The Below line shows that,
navigationController.viewControllers = #[[self.storyboard instantiateViewControllerWithIdentifier:#"second"]];
You are trying to access the array of ViewControllers, but I am not sure why you want all the ViewControllers. I think you can get the secondViewController like this below and set the string
secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
secondViewController.urlString = urlString;
After tried every method I could get, find a workaround by using [navigationController.viewControllers[0] setTitle:urlStrings] might works.
Is doing such correctly?

Manage few UIViewControllers in parent view controller

I have UIViewController that contain another two UIViewControllers as properties.
MenuViewController contains:
#property (nonatomic, strong) TeamsViewController *teamsViewController;
#property (nonatomic, strong) ResultsViewController *resultsViewController;
The MenuViewController contains table view and when user tap on the cell "show teams" I need to initialize teamsViewController and show teamsViewController view. The same thing when user press on the cell "show results" but in this case I need to show resultsViewController view.
So, I usually do this is in one way initialize controllers when cell is pressed and call addSubview method that will add controllers view. But I think it is not good solution am I right?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_teamsViewController) _teamsViewController = nil;
_teamsViewController = [TeamsViewController new]
[self.view addSubView:_teamsViewController];
}
Is the method above ok?
There is my hierarchy of view each of them managed by its own controller. So the white you managed by MenuViewController and the gray view managed by ResultViewController and blue view managed by TeamsViewController.
As I said before when I tap on appropriate cell in menu view controller I need to show teams or results. But each of this view has another view controller. Or maybe I confused about view controller paradigm? Maybe TeamsViewController should be a TeamsView and ResultsViewController should be ResultsView ? So both view controllers has the table as well that managed in their controllers. So i don't think it has to be a UIView instead of UIViewController.
I think your best bet is to set this up as a UINavigationController. UINavigationController inherits from UIViewController so you aren't losing any functionality this way. You could then set it up like this:
//MenuViewController.h
#interface MenuViewController : UINavigationController
#property (nonatomic, strong) TeamsViewController *teamsViewController;
#property (nonatomic, strong) ResultsViewController *resultsViewController;
//Insert other properties and methods....
#end
and in the method called when someone clicks on a cell, you would simply do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.teamsViewController) {
self.teamsViewController = [[UIViewController alloc] initWithNibName:#"nibName" bundle:nil];
}
[self pushViewController:self.teamsViewController animated:YES];
}
Now, you have two view controllers, so you have to tell your method above which one to push onto the stack. If the rows are fixed, you can simply decide which one to show based on indexPath but if it's more dynamic (i.e. tableview is created from a database) then you'll need to have some more complex logic code here.
Without making too many assumptions, but to give you some general guidance, when you create a cell you would generally set some sort of flag on it to indicate what type it is. This can be done with an NS_ENUM or with a simple BOOL if you only have two states (I prefer to use ENUMs whenever possible as they are much more descriptive). You would then check for the existence of that flag in the tableView:didSelectRowAtIndexPath: method, pushing the corresponding view onto the navigation stack. Something like this (this is not literal code, but shown just to give you an idea:
// This code assumes in the method tableView:cellForRowAtIndexPath:
// you have set the tag property to '1' if a TeamsViewController is
// needed or '2' if a ResultsViewController is needed when that cell
// is pressed.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.teamsViewController = self.teamsViewController ? self.teamsViewController : [[UIViewController alloc] initWithNibName:#"TeamsViewController" bundle:nil];
self.resultsViewController = self.resultsViewController ? self.resultsViewController : [[UIViewController alloc] initWithNibName:#"ResultsViewController" bundle:nil];
switch ([[tableView cellForRowAtIndexPath:indexPath] tag]) {
case 1:
[self pushViewController:self.teamsViewController animated:YES];
break;
case 2:
[self pushViewController:self.resultsViewController animated:YES];
break;
default:
break;
}
}
You would still need to do your initialization in your teams or results view controller to show the view but this should steer you in the general direction.
I'd recommend using Storyboards and making sure to have a "Storyboard ID" for each of them. That way, it becomes a bit easier to push various UIViewController instances, as needed. This is my typical pattern:
UIViewController *vc = [self.storyboard
instantiateViewControllerWithIdentifier:#"selected identifier"];
[self.navigationController pushViewController:vc animated:YES];
Also, unless you need to set properties in the child view controller, there's no need to have a property reference to it. Further, this answer assumes that you're using a UINavigationController, with your MenuViewController set as the rootViewController. You can either set this up in IB with a Storyboard (easy and probably the preferred way), or in code like this:
MenuViewController *vc = [[UIViewController alloc] initWithNibName:#""
bundle:nil];
UINavigationController *navVc = [[UINavigationController alloc]
initWithRootViewController:vc];

Setting variable in one view controller for another, and swapping to that view controller

Ok, so i have an interesting situation here:
I have a calendar View, this view does not have a navigation bar, so i created another View to contain the Calendar and added a navigation bar to that view.
So now i have 2 Views displaying a navigation bar and a calendar.
The navigation bars has a butten that is supposed to present a "Insert" controllers, but before it does that, it has to set a #property from the calendar to the "Insert" view controller.
So to sum it up:
Outer View Controller IBAction -> Inner Calendar Set Property on "Insert" -> Inner Calender Present "Insert".
Here is the code:
ViewControllerCalendarContainer.h
#import <UIKit/UIKit.h>
#interface ViewControllerCalendarContainer : UIViewController
- (IBAction)SeguqInsert:(id)sender;
#end
ViewControllerCalendarContainer.m
#import "ViewControllerCalendarContainer.h"
#import "CalendarMonthViewController.h"
...
- (IBAction)SeguqInsert:(id)sender {
CalendarMonthViewController *controller = [[CalendarMonthViewController alloc] initWithNibName:nil bundle:nil];
[controller SegueInsert];
}
CalendarMonthViewController.h
#property (nonatomic, strong) NSDate *dateSelected; // data to send to Insert View Controller
- (void)SegueInsert; // the present "Insert View Controller Method"
CalendarMonthViewController.m
#import "CalendarMonthViewController.h"
#import "ViewControllerInsert.h"
- (void)SegueInsert {
NSDate *dateUserSelected = self.dateSelected;
ViewControllerInsert *controller = [[ViewControllerInsert alloc] initWithNibName:#"ViewControllerInsert" bundle:nil];
controller.dateSelected = dateUserSelected; // set property in Insert
[self presentViewController:controller animated:YES completion:nil]; // present
}
Runtime error on click:
on whose view is not in the window hierarchy!
PS: I cannot Segue via Storyboard, since it uses another instance, and the property that is supposed to get set, does not get set.
Wain is right. The extra view controller is causing a problem. However, I don't think you will be able to just move the code over. You should keep a pointer to your calendar in your navigation controller and just set the property in SequqInsert. Something like this:
#import <UIKit/UIKit.h>
#interface ViewControllerCalendarContainer : UIViewController
#property (weak, nonatomic) CalendarMonthViewController *calendarViewController;
- (IBAction)SeguqInsert:(id)sender;
#end
#import "ViewControllerCalendarContainer.h"
#import "CalendarMonthViewController.h"
...
- (IBAction)SeguqInsert:(id)sender {
NSDate *dateUserSelected = self.dateSelected;
ViewControllerInsert *controller = [[ViewControllerInsert alloc] initWithNibName:#"ViewControllerInsert" bundle:nil];
controller.dateSelected = calendarViewController.dateUserSelected; // set property in Insert
[self presentViewController:controller animated:YES completion:nil]; // present
}
If you're worried about keeping a pointer to the calendar, you can always use protocols to acquire the information.
You seem to have added a view controller that you don't need. The error is because you never show that view controller and then try to present another view controller from it.
Take the code in SegueInsert and move it to SeguqInsert. Then delete the CalendarMonthViewController (which presumably isn't doing anything else and has no other code).

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.

initWithNibName help: returning blank screen when trying to pass data

Ok so I am trying to pass a string from one view controller to another via the AppDelegate. I want to stay on the current view while this happens.
This is the main body of the code I am currently using to do this:
AppDelegate *dataCenter = (AppDelegate *)[[UIApplication sharedApplication] delegate];
MyMealViewController *vc = [[MyMealViewController alloc] initWithNibName:nil bundle:nil];
dataCenter.selectedMenuItem = recipeLabel.text;
[self presentViewController:vc animated:YES completion:NULL];
When I run the program I am able to confirm that the string is correctly passed. However, then the view on the simulator just turns black. I assume that this is because initWithNibName is set to nil.
So my question is: how should I change my code so that the string will still be passed, but the current view will continue to be displayed on the iphone. Is there a line of code that I could write that would just reload the current view?
Thanks for your help with this issue. I am new to xcode so I may be making a very basic error. Please let me know if any additional information would be helpful in answering this question.
Edit: It looks like you want to show a list of food items in the first view. Tapping an items opens a detail view. From that detail view, the user can press a button to add it to the meal. Eventually, they can tap a button on the first view to open the meal view, which should contain all of the items that they selected.
If this is the case, keep an array on the first view controller, and make sure the detail (second) view controller has a reference to the first view controller when it is presented. This will let us use that array. Note that there are better ways to architect this, but this will work for now:
#interface FoodListViewController : UIViewController
#property (strong, nonatomic) NSMutableArray *foodItems
#end
#implementation FoodListViewController
- (void)showFoodItem
{
FoodItemDetailViewController *detailViewController = [[FoodItemDetailViewController alloc] initWithNibName:nil bundle:nil];
detailViewController.foodListController = self;
[self presentModalViewController:detailViewController animated:YES];
}
#end
Once the detail view is presented, tapping the 'add to meal' button should add the current 'mealItem' to the array. In your example, you were using strings - if you would rather keep an array of strings for some reason, I'll leave that to you.
#interface FoodItemDetailViewController : UIViewController
#property (nonatomic, weak) FoodItemsViewController *foodListController;
#end
#implementation FoodItemDetailViewController
- (IBAction)buttonTapped:(id)sender
{
[self.foodListController.foodItems addObject:self.mealItem];
// Update the UI to let the user know that the item was added to the meal
}
#end
Finally, when it comes time to present the MealDetailsViewController, just pass it the array that you have been building:
#interface MealDetailsViewController : UIViewController
#property (nonatomic, strong) NSArray *foodItems;
#end
#implementation MealDetailsViewController
// Set foodItems before this view controller is presented, then use it to drive the
// UITableView data source, or find some other way of displaying it.
#end
As you can see, both the second and third view controllers are presented by the first. View controllers (nearly) always form a hierarchy - so keeping your data at the top of that hierarchy (by storing it in FoodListViewController) lets you neatly pass it down the hierarchy as you present other view controllers.

Resources