Passing data between the Tabs of a TabBarViewController - ios

I have a UITabBarController based application and I want to pass data from one view to another. I am doing this in storyboard and I am just doing some testing, before bringing it into the main application.
I am just trying this with a NSString at the moment.
I am able to pass data to the VC in question when I use a modal transition using this code:
NSString *sendingString = #"This string has some content";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
NextViewController *nVC = (NextViewController *)[storyboard instantiateViewControllerWithIdentifier:#"goToNextVC"];
nVC.receivingString = sendingString;
[self presentViewController:nVC animated:YES completion:nil];
Now this pushes that VC up and passes it as I want it, but instead of pushing up the VC I want it to be pushed to another Tab Bar.
Now I can flick to the desired TabBar with this code:
self.tabBarController.selectedIndex = 1;
Where I get stuck is, how do I send data to this ViewController???

You could either subclass your TabBarController, and add a property to it, or create a singleton (e.g. DataManager), to which all your ViewControllers will have access. You can pass your data to it.

Related

IOS/Objective-C/Storyboard: Prevent ViewController From Launching Modally

I want a viewcontroller to launch using a show transition, not modally from the bottom. Normally when I use the following code that's what happens. However, in this case, it is launching as a modal controller from the bottom up. Is there a switch I don't know about or could something be set in Storyboard that is causing this VC to launch modally from the bottom instead of showing?
UIStoryboard *storyBoard = self.storyboard;
IDImportEventsOnboard *importEvents =
[storyBoard instantiateViewControllerWithIdentifier:#"importEventsOnboard"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: importEvents];
[self presentViewController:nav animated:YES completion: nil];
The VC is embedded in a navigation controller.
Should I be using showViewController directly to the targetVC without going through the Nav? Or a pushViewController What is a proper, robust way to show a VC with a show transition?
Thanks in advance for any suggestions.
In the above code you are 'presenting' a new NavigationController from a ViewController. In order to do a push/show transition, that needs to be done on an instance of a NavigationController. If your current ViewController is already in a NavigationController, you can push the new ViewController onto the current NavigationController stack. For Example:
UIStoryboard *storyBoard = self.storyboard;
IDImportEventsOnboard *importEventsVC =
[storyBoard instantiateViewControllerWithIdentifier:#"importEventsOnboard"];
[self.navigationController pushViewController:importEventsVC animated:YES];

Initialize ViewController with data and programmatically show it to screen

The storyboard of my iOS application contains a NavigationController with a root ViewController. From a secondary view controller, I would like to programmatically display the root VC with the attached NavigationController showing at the top, and at the same time instantiate the root VC with some data.
I have the following so far in the secondary view controller:
UINavigationController* nav = [[UIStoryboard storyboardWithName:#"Storyboard" bundle:nil] instantiateViewControllerWithIdentifier:#"NavController"];
UIViewController* viewController = [[UIStoryboard storyboardWithName:#"Storyboard" bundle:nil] instantiateViewControllerWithIdentifier:#"RootVC"];
viewController.data = #"My test data";
[self presentViewController:nav animated:YES completion:nil];
The root VC displays successfully with the navigation bar along the top, however when I print the following in the rootVC logic, it comes out as null:
NSLog(#"Initialized data: %#", self.data); // null
How can I fix this? It seems that the initialized data is not coming through from the secondary controller.
You are creating a new instance of UIViewcontroller which has identifier "RootVC" and assigning data to it.
Instead, you should assign the data to rootViewController of navigation controller something like this:
self.navigationController.viewControllers.firstObject.data = #"My test data";
It is a problem of different instances of same class.

How to pass value to a viewController embedded in NavigationController

There are similar questions but they are either in swift or are not solving my problem.I've a view controller which is presenting navigation view controller when cell did select button is pressed as:
patientBillNavigationViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PatientBillVC"];
//soem value assignment
[self presentViewController:viewController animated:YES completion:nil];
You can say billing opens up a whole new view independent of the main app flow to handle billing process.
The view this navigation View Controller automatically loads is the bill view and now if I want to pass a value from this viewcontroller to the other viewController embedded in navigation view I can't do that. How to pass a value?
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
PatientBillViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"PBVC"];
vc.superBillToAddEdit = sb;
//then display the view embedded in navigation view
But this is not working.
One way I know is to Subclass UINavigationViewController and in its viewDidLoad, you can do:
YourEmbeddedVc *svc =self.viewControllers[0]; //get the controller reference
svc.name= #"Hello";
I'm assuming you are only having one controller in your navigation stack, if not you need to find out the proper match of the required VC.
I might not be understanding the question exactly, correct me if I'm wrong.
It sounds like you want to start a nav controller from a view controller (let's call this firstViewController) and pass a value from firstViewController to the view controller that will eventually load in the nav controller.
If that's the case, why don't you create the second view controller (billingStep1ViewController) and then assign the value to it as a property, then pass the billingStep1ViewController to the nav controller's initWithRootViewController: method?
Something like this (untested code, btw):
// this code would go inside our FirstViewController file
// create the first vc that will be loaded in the nav controller
BillingStep1ViewController *billingStepOneVc = [self.storyboard instantiateViewControllerWithIdentifier:#"stepOne"];
// set the value you want
billingStepOneVc.bill = myBill;
// create new nav controller with step one vc as the root
UINavigationController *uiNavController = [[UINavigationController alloc] initWithRootViewController:billingStepOneVc];
[self presentViewController:uiNavController];
That way you can have two view controllers talking directly with one another and not worry about the navigation controller at all.
Update: Here is some tested code that works to illustrate my idea:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
//create the step 1 view controller - this is the first view controller we will see in the navigation controller
StepOneViewController *stepOneVc = [storyboard instantiateViewControllerWithIdentifier:#"stepOne"];
//assign a value to it (name is an NSString #property of StepOneViewController)
stepOneVc.name = #"Jones";
//this is the nav controller we will display, we set the root vc to our step one.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:stepOneVc];
//present the nav controller on screen.
[self presentViewController:navController animated:YES completion:nil];
Some of the class names changed but the idea is the same.
Rather than creating the navigation controller from its storyboard identifier, create it programmatically, with the PatientBillViewController you created as its root view controller. Like this:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
PatientBillViewController *pbVC = [mainStoryboard instantiateViewControllerWithIdentifier:#"PBVC"];
pbVC.superBillToAddEdit = sb;
PatientBillNavigationViewController * navVC = [[PatientBillNavigationViewController alloc] initWithRootViewController:pbVC];
[self presentViewController:navVC animated:true completion:nil];
Swift Version
Here is the swift version answer for the above problem!!
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PatientBillVC") as! patientBillNavigationViewController
vc.name = "name"
let mVc = UINavigationController.init(rootViewController: vc)
self.navigationController?.present(mVc, animated: true, completion: nil)

IOS/objective-c/xcode: Instantiate DetailView Controller in Code

I had some code for launching a modal view controller created in storyboard with a storyboard ID. For a new situation, I am trying to adapt it to present a ViewController that is actually the detail view of a table in the main navigational system. I'm trying to jump around in the app if that is possible.
In this case, the VC should not be modal. Instead, I want to take the user to the normal detail view of a table.
To make it more challenging, I need the detail view to have the object data. Fortunately, this should be present in the starting VC.
Here is my code for launching a modal VC.
UIStoryboard *storyBoard = self.storyboard;
detailVC *newVC =
[storyBoard instantiateViewControllerWithIdentifier:#"detailView"];
//pass object to new VC
detailVC.object = _object;//pass data object
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: dareVC];
[self presentModalViewController:nav animated:YES];
Edit: Following code does launch non-modal VC. However, initial detail view is devoid of data. The data is saved so if I come back to it, the data is there but initially, I get generic screen with no data.
detailVC *secondViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[self.navigationController pushViewController:secondViewController animated:YES];
secondViewController.object=_object;
detailVC *secondViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
secondViewController.object=_object;
[self.navigationController pushViewController:secondViewController animated:YES];
First instantiate it.
Then set the data.
Then push it.

Attempt to present a viewcontroller whose view is not in the window hierarchy

I have a tab bar application. My requirement is I select the 'scan' tab to scan the qr code and navigate/jump immediatley to another 'list' tab. Both 'scan' and 'list' tab are there in the viewControllers array in didFinishLaunchingWithOptions After referring this link, i don't think i need to set the delegate as both the tabs are already present in the hierarchy.
I get this warning in the following line
if(x)
{
listViewCntrl = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
listViewCntrl.getFlag = YES;
[self presentViewController:listViewCntrl animated:YES completion:Nil]; // I get the warning here
}
If I comment out the above code and add
[self.tabBarController setSelectedIndex:1];
then I would not be able to get the subView of the listViewController (set flag to show the subview) which i need to display inside the list tab after scanning.
App crashes if I add
[self.tabBarController setSelectedViewController:listViewCntrl];
So how do I display the listView's subview after scanning?
You can try this if you use storyboard:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ViewController * destViewController = [storyboard instantiateViewControllerWithIdentifier:#"ViewControllerIdentifier"];
[self.navigationController pushViewController:destViewController animated:YES];
You have to set an identifier for your controller in your storyboard.
ListViewController *listController = (ListViewController*)[self.tabController viewControllers][1];
listController.getFlag = 1;
[self.tabBarController setSelectedIndex:1];
The problem is that you're creating an entirely new ListViewController. You say you already have one in the tab controller - you don't need a new one.
You can't use your 3rd option because, again, the two ListViewController's are different objects (they may be of the same class, but they point to a different address).

Resources